无锁队列是怎么入队出队的?什么时候不如带锁队列?这篇不画 CAS 的示意图,而是直接测它的弱一致性、size 的代价、顺序保证和线程数增加时的吞吐(BlockingQueue 的阻塞语义见前一篇)。
队列 [1,2,3] 先创建迭代器,之后 add(4)、remove(2)、add(5):迭代器看到 [1, 3, 4, 5](弱一致:不抛 ConcurrentModificationException,看到的是创建迭代器之后又发生的部分变化) add(null) → NullPointerException(不允许 null 元素) 空队列 poll() = null,peek() = null(不阻塞)
1,000 个元素:ConcurrentLinkedQueue.size() 2,099 ns;LinkedBlockingQueue.size() 16 ns;ConcurrentLinkedQueue.isEmpty() 44 ns
100,000 个元素:ConcurrentLinkedQueue.size() 229,068 ns;LinkedBlockingQueue.size() 4 ns;ConcurrentLinkedQueue.isEmpty() 21 ns
1,000,000 个元素:ConcurrentLinkedQueue.size() 2,648,479 ns;LinkedBlockingQueue.size() 0 ns;ConcurrentLinkedQueue.isEmpty() 10 ns4 个生产者各并发入队 200000 个元素,单线程依次出队:共 800000 个,每个生产者自己的元素出队顺序乱序的次数 = 0(每个生产者内部保持先进先出);不同生产者的元素在队列里交错了 382735 次
ConcurrentLinkedQueue 1 个线程各自反复 offer+poll:88.4 百万次操作/秒 ConcurrentLinkedQueue 2 个线程各自反复 offer+poll:22.4 百万次操作/秒 ConcurrentLinkedQueue 4 个线程各自反复 offer+poll:9.7 百万次操作/秒 ConcurrentLinkedQueue 8 个线程各自反复 offer+poll:8.7 百万次操作/秒 LinkedBlockingQueue 1 个线程各自反复 offer+poll:57.1 百万次操作/秒 LinkedBlockingQueue 2 个线程各自反复 offer+poll:13.2 百万次操作/秒 LinkedBlockingQueue 4 个线程各自反复 offer+poll:29.5 百万次操作/秒 LinkedBlockingQueue 8 个线程各自反复 offer+poll:34.9 百万次操作/秒