Java线程池饱和时由拒绝策略处理新任务,四种内置策略各具特点:AbortPolicy默认抛异常适合关键链路;CallerRunsPolicy让调用线程执行以反压;DiscardPolicy静默丢弃适合幂等任务;DiscardOldestPolicy挤掉队头任务适用于时效性强场景。

Java线程池饱和时,任务无法被立即执行,此时由拒绝策略(RejectedExecutionHandler)决定如何处理新提交的任务。核心逻辑是:当线程数已达最大值 且 工作队列已满,后续任务就会触发该策略。四种内置策略各有侧重,选错可能引发丢任务、阻塞调用线程或服务雪崩。
AbortPolicy:默认中断,快速失败
这是 ThreadPoolExecutor 的默认策略。一旦饱和,直接抛出 RejectedExecutionException,不重试、不丢弃、不回退——只通知调用方“我处理不了”。
- 适合对任务完整性要求极高的场景,比如支付扣款、订单创建等关键链路
- 调用方必须捕获异常并做兜底,例如降级、重试、写入死信队列
- 缺点是容易导致上游请求失败,若无容错机制,可能放大故障影响
CallerRunsPolicy:让调用者减速执行
不抛弃任务、不抛异常,而是把被拒任务交还给 提交任务的线程(如 main 线程)来同步执行。本质是一种反压机制。
- 能自然降低任务提交速率,给线程池腾出执行空间
- 适用于非实时性要求高、允许调用线程短暂阻塞的后台任务
- 需警惕:若调用线程本身负载高或持续提交任务,可能导致其卡死,甚至拖垮整个应用
DiscardPolicy:静默丢弃最新任务
新任务到达时,如果线程池已饱和,就直接丢弃,不抛异常、不通知、不记录。
立即学习“Java免费学习笔记(深入)”;
- 适合可丢失、幂等性强的任务,比如日志采集、监控埋点、缓存预热
- 实现最轻量,零开销,但缺乏可观测性,问题排查困难
- 建议配合监控告警使用,例如统计 reject 次数突增时自动告警
DiscardOldestPolicy:挤掉队头任务再尝试提交
先从工作队列头部移除一个等待最久的任务(即即将被执行的那个),再把当前新任务加入队列尾部,重新尝试提交。
- 适用于任务有较强时效性、但队列中旧任务价值已衰减的场景
- 不能用于优先级队列(PriorityBlockingQueue),否则可能误删高优任务
- 注意:移除操作本身有并发开销,高频饱和下可能带来额外性能损耗
策略不是固定配置,而是系统负载特征与业务语义的映射。上线前应结合压测数据和任务重要性分级选择,并确保监控覆盖 reject 计数与异常日志。不复杂但容易忽略。


















