Doug Lea关于ArrayBlockingQueue与LinkedBlockingQueue表述的疑问求解
关于Doug Lea对ArrayBlockingQueue与LinkedBlockingQueue的表述答疑
问题1:Aren't allocating the things put into queues指代的具体场景
这句话核心指「放入队列的元素不需要临时分配内存」的场景,常见的有三类:
- 元素是提前预分配好的对象池成员:比如提前初始化了一批任务对象,全程复用这些对象入队、消费后放回对象池,全程没有新对象创建
- 放入队列的是全局常驻的静态对象、枚举值:比如用队列传递状态枚举、单例信号对象,这类对象JVM启动后就常驻内存,不会因为入队出队产生新分配
- 队列传递的是基础类型包装类常量:比如Integer缓存范围内的数值、Boolean的TRUE/FALSE对象,这类对象也不需要临时分配内存
这种场景下,整个入队出队流程原本就没有新对象的创建销毁,LinkedBlockingQueue的Node节点每次入队分配新对象、出队后变成垃圾的额外开销就会凸显,原本可以忽略的GC影响会变成明显的性能损耗。
问题2:队列既非空也非满且无大量线程竞争时ArrayBlockingQueue更优的原因
要理解这个结论,首先得明确两个队列的核心实现差异:
ArrayBlockingQueue底层是固定长度的数组,入队出队只用移动游标,所有操作共用一把重入锁;出队元素后直接把对应数组位置置空,没有额外对象操作。
LinkedBlockingQueue底层是链表实现,为了提升并发度做了入队锁、出队锁分离,入队要新生成Node对象、赋值next指针,出队要把旧Node置空等待GC。
满足前提条件时,ArrayBlockingQueue的优势主要体现在三点:
- 无锁分离的额外开销:因为没有大量竞争,LinkedBlockingQueue的双锁设计完全发挥不出优势,反而加锁解锁的次数、锁的内存屏障开销和ArrayBlockingQueue持平甚至更高
- 内存局部性更好:数组是连续内存空间,CPU缓存命中率远高于链表的离散Node节点,存取元素的速度要快很多
- 无额外对象开销:不需要创建/销毁Node对象,既省了分配对象的CPU开销,也没有Young GC的额外压力,整体吞吐量更稳定
如果不满足这个前提,比如队列经常处于空/满状态,线程需要频繁阻塞唤醒,或者并发量很高,LinkedBlockingQueue的双锁可以支持一边入队一边出队的并发操作,扩展性就会比单锁的ArrayBlockingQueue好很多。
内容的提问来源于stack exchange,提问作者woxihuanxiayua
相关产品推荐
相关产品推荐

