arrayblockingqueue 和 linkedblockingqueue 的选择需综合容量控制、内存开销、锁机制、gc 压力及时序要求:前者容量强制、内存紧凑、单锁可控,适合高吞吐与资源受限场景;后者默认“伪无界”易致 oom,双锁在频繁中间操作时反而更慢,且节点开销大、gc 压力高。

有界队列必须显式指定 capacity,否则编译不报错但运行时会出问题
ArrayBlockingQueue 在构造时 capacity 是强制参数,不传直接编译失败;而 LinkedBlockingQueue 的 capacity 是可选的——不传就默认用 Integer.MAX_VALUE(≈21亿),表面“无界”,实则极易掩盖内存泄漏或背压失控问题。
- 线上曾有服务因误用无参
new LinkedBlockingQueue(),突发流量把堆撑爆 OOM,GC 频繁但找不到明显大对象 - ArrayBlockingQueue 一旦容量设小(比如
new ArrayBlockingQueue(10)),生产者调用put()会立刻阻塞,能天然暴露吞吐瓶颈 - 如果真需要“逻辑无界”,建议显式写成
new LinkedBlockingQueue(Integer.MAX_VALUE),至少让容量意图可见
高并发读写分离场景下,LinkedBlockingQueue 的双锁机制未必更快
LinkedBlockingQueue 在 JDK 8+ 中确实用了 takeLock 和 putLock 两把锁,理论上允许生产和消费并行。但实际中,若存在频繁 remove()、contains() 或遍历操作,它反而要同时抢两把锁,比 ArrayBlockingQueue 的单锁更慢。
-
remove(Object o)在 LinkedBlockingQueue 中需先加putLock再加takeLock,锁竞争剧烈 - ArrayBlockingQueue 的数组结构支持 O(1) 定位
takeIndex和putIndex,缓存友好,在 CPU 密集型场景吞吐更稳 - 除非你的典型负载是「持续大批量入队 + 持续大批量出队」且几乎不用中间操作,否则别迷信“双锁=高性能”
内存占用和 GC 压力差异远比想象中大
ArrayBlockingQueue 用一个连续数组,对象头 + 数组本身,内存紧凑;LinkedBlockingQueue 每个元素都包装成 Node 对象(含 item + next 引用),哪怕只存 Integer,也要多分配 24~32 字节(取决于 JVM 布局)。
- 存 10 万个
String,LinkedBlockingQueue 多产生约 2~3MB 额外对象,GC 频率明显上升 - ArrayBlockingQueue 的数组扩容不可行,但好处是内存始终可控;LinkedBlockingQueue 表面灵活,却把压力转嫁给 GC
- Android 或资源受限环境,优先选 ArrayBlockingQueue —— 链表节点碎片化对低内存设备更不友好
公平性与线程唤醒顺序影响任务时效性
两者都支持构造时传 fair = true,但行为不同:ArrayBlockingQueue 的公平锁会让等待最久的线程优先获取锁;而 LinkedBlockingQueue 的 notEmpty/notFull 条件队列在公平模式下,唤醒顺序才真正按 FIFO 排。
- 秒杀场景中,若用非公平
ArrayBlockingQueue,后到的请求可能插队成功,导致先排队的用户超时失败 - 但开启公平模式会降低吞吐——JVM 要维护线程等待队列,每次唤醒都要遍历
- 真正对时序敏感的业务(如订单超时取消),别只依赖队列公平性,应在业务层加时间戳+优先级判断










