必须显式设置LinkedBlockingQueue容量,避免默认Integer.MAX_VALUE导致OOM;容量需按峰值速率、处理能力与容忍等待时间计算,并配套拒绝策略与监控。

不能靠“调大容量”防 OOM,而要让 LinkedBlockingQueue 的容量可算、可控、可响应。默认无界(Integer.MAX_VALUE)看似安全,实则是把内存压力延后引爆——任务持续堆积,每个 Runnable 或 DTO 占几百字节,几万条就吃掉百 MB 堆内存。
必须显式设容量,别用无参构造
LinkedBlockingQueue 默认无界,本质是“假稳定、真风险”。生产环境务必传入明确容量值:
- 写法必须是
new LinkedBlockingQueue(256),绝不能是new LinkedBlockingQueue() - 容量不是越大越好:设 10000 不等于更稳,只是把 OOM 推迟几小时;设太大还会掩盖真实吞吐瓶颈
- 推荐起步值:512、1024、2048 —— 具体取决于单任务对象大小和堆可用空间(例如单任务约 800B,预留 128MB 堆缓冲,则上限 ≈ 160_000,但实际建议取 1/3~1/2 作为队列容量)
容量要按业务节奏算,不是拍脑袋
合理容量 = 峰值提交速率 × 最大容忍等待时间 ÷ 平均处理速率。这个公式反映的是系统能“缓多久”的真实能力:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
- 例如:订单入口每秒进 1500 个任务,线程池每秒最多处理 600 个,允许用户最长等 2 秒 → 理论积压上限 = 1500 × 2 − 600 × 2 = 1800 条
- 再加 20% 缓冲,设为 2160,四舍五入取 2048 是合理选择
- 若估算出的值远超 10000,说明要么处理能力严重不足,要么上游限流缺失——这时该优化处理逻辑或加前置熔断,而不是堆大队列
搭配拒绝策略,让“满”变成信号而非故障
有界之后,队列满是常态,关键是怎么响应:
立即学习“Java免费学习笔记(深入)”;
- 禁用
AbortPolicy(只抛异常),尤其在 HTTP 接口层,会导致请求直接 500 -
CallerRunsPolicy可用,但要注意:高并发下会让 Web 容器线程自己执行任务,可能拖慢响应、推高 GC 频率 - 更推荐自定义策略:记录日志 + 上报 Prometheus 指标(如
queue_rejected_total) + 触发降级(返回兜底数据或写本地文件暂存) - 对强一致性场景,可溢出到 Redis 列表:队列满时自动落库,后台定时捞回重试,兼顾不丢与防 OOM
注意线程数与队列的协同关系
光设容量不够,还要看它和线程池怎么咬合:
- 核心线程数 ≠ 最大线程数?比如设成 4 和 32,又配了大容量队列,容易导致大量任务长期滞留队列,线程却空闲——资源错配
- 建议初期保持 corePoolSize == maxPoolSize(如都设为 8),确保稳定消费能力;再根据监控数据(如 activeCount、queueSize 趋势)动态调整
- 避免“小线程池 + 大队列”组合:4 个线程配 10000 容量,等于人为制造长尾延迟,也放大内存占用

















