ArrayBlockingQueue单锁双Condition,生产消费串行争锁;LinkedBlockingQueue双锁分离,吞吐高40%+;SynchronousQueue无锁handoff,零内存开销、延迟最低。选型取决于是否需要缓冲及场景需求。

ArrayBlockingQueue:单锁 + 双 Condition
ArrayBlockingQueue 使用一把 ReentrantLock,同时控制入队(put/offer)和出队(take/poll)操作。生产者和消费者必须竞争同一把锁,无法并行执行——哪怕一个在数组尾部写、一个在头部读,逻辑上互不干扰,仍需串行抢锁。
它配合两个 Condition 实现阻塞等待:notEmpty 用于消费者等待元素,notFull 用于生产者等待空位。这两个 Condition 共享同一把锁,因此唤醒后仍要重新争锁。高并发下易出现锁等待占比高、上下文切换频繁等问题,实测 16 线程时锁等待常超 30%。
优势在于内存局部性好、GC 压力小、实现简洁;适合中低并发、对延迟不敏感或需要强一致性的场景。
LinkedBlockingQueue:双锁分离(putLock + takeLock)
LinkedBlockingQueue 显式拆分为两把独立的 ReentrantLock:putLock 专管入队,takeLock 专管出队。生产者只持 putLock,消费者只持 takeLock,真正实现读写分离。
每把锁各自绑定一个 Condition:notFull(挂起生产者)、notEmpty(挂起消费者)。当队列非空时,消费者可立即获取元素而不干扰正在入队的线程;反之亦然。这种设计显著降低锁竞争,在 16 线程压测中吞吐量比 ArrayBlockingQueue 高 40%+。
注意:遍历或删除中间元素时需同时持有两把锁,此时并发优势消失;默认容量为 Integer.MAX_VALUE,若不限制易引发 OOM,建议显式指定容量。
SynchronousQueue:无锁化协作(非公平模式用 Treap,公平模式用 CLH)
SynchronousQueue 不依赖传统意义上的“队列锁”。它没有内部存储,不维护元素数组或链表,因此也无需保护数据结构本身。其核心是线程间的直接 handoff(交接),通过无锁算法协调生产者与消费者配对。
非公平模式下使用 Treap 树组织等待线程,追求极致吞吐,但可能造成部分线程长期得不到调度(饥饿);公平模式则基于 CLH 队列实现 FIFO 等待,保证严格顺序,适合实时性要求高的系统。
关键操作如 put() 和 take() 本质是自旋 + 阻塞混合:先尝试 CAS 快速匹配,失败后进入 park 状态;状态字段用 volatile 保证可见性,Thread.onSpinWait() 协助 JVM 优化 CPU 自旋。它不占内存存元素,每元素内存开销为 0 字节,延迟最低(JMH 测试 50% 延迟仅 0.8μs)。
选型关键看协作模式而非容量
三者差异不在“有没有容量”,而在于“要不要缓冲”:
- 要缓冲解耦 → 选 LinkedBlockingQueue(均衡吞吐与可控内存)或 ArrayBlockingQueue(简单确定、内存友好)
-
不要缓冲、强同步 → 选 SynchronousQueue(如
newCachedThreadPool()默认队列,任务来即转交空闲线程) - 缓冲大小必须固定且可控 → ArrayBlockingQueue 更直观(数组长度即容量上限)
- 突发流量下需弹性缓冲 → LinkedBlockingQueue(设合理上限防 OOM)

















