已有LinkedBlockingQueue,为何还要使用ConcurrentLinkedQueue?
ConcurrentLinkedQueue vs LinkedBlockingQueue:你的观察补充与细节梳理
嘿,你对这两个并发队列的观察挺到位的!我来帮你把这些点梳理得更清楚,补充些你可能没注意到的细节:
核心特性与定位
- ConcurrentLinkedQueue:纯非阻塞队列,完全依靠**CAS(比较并交换)**这种硬件级别的原子操作实现线程安全,全程无锁。这意味着它在高并发场景下的锁竞争开销极低,不会出现线程阻塞等待的情况,天生就是为高吞吐量的并发场景设计的。
- LinkedBlockingQueue:本质是可选有界/无界的阻塞队列——默认构造出来是无界的(容量为
Integer.MAX_VALUE),你也可以手动指定固定容量。它基于ReentrantLock实现线程安全,当队列满(有界场景)时put()会阻塞线程,队列空时take()会阻塞线程;但你提到的offer()和poll()确实是非阻塞的:offer()在队列满时直接返回false,poll()在队列为空时直接返回null,这也是你能把它当作非阻塞队列使用的核心原因。
常用操作的一致性与差异
你提到的操作确实适用于两者,但有个小细节要注意:
- 插入元素:
LinkedBlockingQueue支持put()(阻塞)和offer()(非阻塞);而ConcurrentLinkedQueue因为是无界队列,永远不会出现插入失败的情况,所以只提供offer()方法,没有put()。 - 移除元素:两者的
poll()行为完全一致——队列为空时直接返回null,不会阻塞等待。
你提到的CAS机制之外的关键区别
除了CAS这个核心实现差异,还有这些点会影响你选择队列:
- 迭代器特性:
ConcurrentLinkedQueue的迭代器是弱一致性的,迭代过程中不会抛出ConcurrentModificationException,也不会完全反映迭代开始后的所有队列修改;而LinkedBlockingQueue的迭代器是快速失败的,迭代期间如果队列被外部修改(除了迭代器自身的remove()),会立刻抛出异常。 - 内存一致性:
ConcurrentLinkedQueue的CAS操作自带内存语义,遵循happens-before原则;LinkedBlockingQueue则依靠锁的内存屏障来保证内存可见性,语义更直观。 - 性能表现:在高并发、线程数量多的场景下,
ConcurrentLinkedQueue的吞吐量通常更高,因为没有锁竞争带来的开销;但如果是低并发场景,或者你需要阻塞等待的能力(比如生产者消费者模型里需要等待队列有空间/有元素),LinkedBlockingQueue的实现更简单易懂,维护成本更低。
内容的提问来源于stack exchange,提问作者sdindiver
相关产品推荐
相关产品推荐

