选arrayblockingqueue还是linkedblockingqueue,关键在于容量控制、锁机制与内存开销的权衡:前者强制有界、单锁互斥、内存紧凑,适合资源敏感场景;后者双锁高吞吐但默认无界易oom,须显式设限。

选 LinkedBlockingQueue 还是 ArrayBlockingQueue,关键不在“快不快”,而在于你愿不愿意为吞吐让渡容量控制权、为并发承担内存风险。
有界性不是可选,而是设计前提
ArrayBlockingQueue 从构造起就强制你面对容量问题:必须传一个正整数容量,否则编译失败。这倒逼你思考——每秒进多少任务?平均耗时多久?能容忍几秒排队?比如 QPS 200、单任务耗时 50ms,理论缓冲需求约 10 个,设成 50 是常见安全余量。
LinkedBlockingQueue 默认无界(Integer.MAX_VALUE),表面省事,实则把背压转移到堆内存。线上曾有服务因未设容量,突发流量写满队列,JVM 堆撑到 95% 后频繁 Full GC,响应延迟飙升。真需要大缓冲,应显式写 new LinkedBlockingQueue(10000),至少让容量意图可见。
锁机制决定谁在等谁
ArrayBlockingQueue 用一把锁管所有操作:插入和取出互斥。任务提交快、执行慢时,生产者常被消费者“卡住”,尤其队列半满以上,吞吐易波动。
LinkedBlockingQueue 拆成两把锁:putLock 只管入队,takeLock 只管出队。生产者塞任务时,消费者照常取任务,高并发下吞吐更稳。但注意:若代码里频繁调用 remove() 或 contains(),它反而要同时抢两把锁,比 ArrayBlockingQueue 更慢。
- 纯高频 submit + execute 场景 → LinkedBlockingQueue 双锁优势明显
- 带中间查询或删除逻辑 → ArrayBlockingQueue 单锁更可控
内存开销差的不是一点半点
ArrayBlockingQueue 初始化就分配连续数组,存 1 万个字符串,就是一块固定内存,GC 几乎不找它麻烦。
LinkedBlockingQueue 每个任务都包装成 Node 对象(含 item + next 引用),存同样 1 万个字符串,多出约 2–3MB 额外对象,长期运行 GC 压力明显。Android 或容器内存受限环境,这点差异足以影响稳定性。
- 资源敏感、延迟要求稳 → 选 ArrayBlockingQueue
- 吞吐优先、内存充足、且能监控堆使用 → LinkedBlockingQueue(务必设容量)
拒绝策略暴露真实瓶颈
ArrayBlockingQueue 队列满时,线程池要么触发拒绝策略(如 AbortPolicy 抛异常),要么启用 CallerRunsPolicy 让调用线程自己执行——这会立刻拖慢上游,但你能第一时间感知负载超限。
LinkedBlockingQueue(尤其无界)会让任务无声堆积,直到 OOM 才报警。它掩盖了问题,而不是解决它。真正健壮的服务,应该让背压“看得见”:队列满 → 拒绝 → 上游降级或重试 → 容量扩容或限流调整。
不复杂但容易忽略:队列不是缓存,是压力计。选哪个,本质是在选你愿以什么方式面对系统瓶颈。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











