线程池饱和策略需匹配业务特性:支付/订单用abortpolicy+有界队列确保强一致;web请求选callerrunspolicy实现负反馈;监控日志类用discardpolicy+丢弃率监控;行情心跳类用discardoldestpolicy保时效。

线程池饱和策略不是“选一个就行”,而是要和业务的容错能力、时效要求、资源敏感度严丝合缝。关键看三点:任务能不能丢、谁来兜底、系统能不能扛住反压。
支付/订单类强一致性场景:用 AbortPolicy + 显式捕获
这类任务一旦提交,就必须成功或明确失败——不能静默丢弃,也不能让调用线程阻塞执行(否则 Web 容器线程被占满会雪崩)。AbortPolicy 抛出 RejectedExecutionException 正好满足:调用方能立即感知,触发重试、降级或告警。
注意两点:
- 必须在 submit/execute 外层 try-catch,不能依赖日志埋点后才处理
- 搭配有界队列(如 ArrayBlockingQueue(200))+ 合理的 maximumPoolSize(比如 20),避免因无界队列掩盖真实过载
Web 请求类高吞吐场景:优先 CallerRunsPolicy
用户请求不能丢,但可以慢一点。CallerRunsPolicy 让 Tomcat/NIO 线程自己执行任务,天然形成负反馈:上游提交越快,调用线程越忙,反而自动压低了新请求进入速度。
适用前提:
- 任务逻辑轻量(执行时间短),否则会拖垮整个请求线程池
- 已限制最大并发连接数(如 Nginx upstream max_conns)、下游接口有超时和熔断
- workQueue 建议设为 50~200 的有界队列,避免堆积过多导致响应延迟不可控
监控埋点/日志聚合类弱一致性场景:DiscardPolicy + 丢弃率监控
这类任务本质是“尽力而为”。DiscardPolicy 静默丢弃最省资源,但前提是:你得知道它丢了多少。
必须配套做两件事:
- 通过 ThreadPoolExecutor.getRejectedExecutionCount() 或 Micrometer 暴露指标,实时监控丢弃率
- 当丢弃率持续 > 1% 时,自动告警并触发扩容(如调整队列容量或增加 maximumPoolSize)
别用无界队列替代——内存耗尽比丢数据更致命。
实时行情/心跳/状态更新类强时效场景:DiscardOldestPolicy
旧数据不仅没用,还可能误导系统。比如股票价格推送,最新价永远比 2 秒前的价重要;设备心跳,刚收到的比积压的 5 条都关键。
注意边界:
- 仅对 FIFO 队列(如 ArrayBlockingQueue)有效,“最老”即队首任务
- 不适用于 PriorityBlockingQueue,因为“最老”不等于“优先级最低”
- 需配合较短的 keepAliveTime(如 10s),让空闲线程快速回收,腾出资源接新任务
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











