java线程池内置4种拒绝策略:1. abortpolicy默认抛异常,适用于高一致性场景;2. callerrunspolicy由调用线程执行任务,实现背压;3. discardpolicy静默丢弃,适合可容忍丢失的任务;4. discardoldestpolicy丢弃队首任务,强调时效性。

Java线程池的拒绝策略共4种内置实现,全部实现了RejectedExecutionHandler接口,用于处理线程池无法接纳新任务时的兜底逻辑。它们不是“可选配置”,而是线程池饱和或关闭时的必经环节,直接影响任务是否丢失、系统是否告警、调用线程是否阻塞等关键行为。
AbortPolicy(中止策略,默认)
当线程池已满(活跃线程达maximumPoolSize且队列已满)或已关闭时,直接抛出RejectedExecutionException异常,任务不执行、不记录、不重试。
- 适用于对任务完整性要求极高的场景,如支付扣款、库存扣减、事务提交等
- 上层必须捕获该异常并做明确处理(如重试、降级、告警),否则会中断调用链
- 不建议在无异常处理机制的代码中直接依赖此策略
CallerRunsPolicy(调用者运行策略)
由提交任务的线程(比如主线程、Web容器线程、定时调度线程)直接执行被拒绝的任务,而非丢弃或抛异常。
- 本质是一种“背压”机制:调用者被阻塞执行,自然降低后续任务提交速率
- 能避免任务丢失,但可能影响调用方响应,例如Servlet线程执行耗时任务会导致HTTP请求超时
- 适合非核心、允许延迟、且不能丢数据的场景,如日志异步刷盘、指标上报
DiscardPolicy(静默丢弃策略)
不做任何操作,直接丢弃被拒绝的任务,不抛异常、不记录、不通知。
立即学习“Java免费学习笔记(深入)”;
- 开销最小,适合高吞吐、低价值、可容忍丢失的任务,如埋点统计、心跳上报
- 风险在于完全无感知——问题发生时难以定位,线上排查困难
- 使用前需确认业务逻辑允许“部分失效”,且有监控手段覆盖丢弃率
DiscardOldestPolicy(丢弃最旧策略)
先从工作队列中移除队首(即等待时间最长)的任务,再尝试将当前任务加入队列;若队列仍满,则最终仍会触发拒绝逻辑(可能再次进入该策略或切换为其他策略)。
- 适用于强调“时效性优于完整性”的场景,如实时行情、消息推送、状态刷新
- 注意:仅对有界队列有效;若使用无界队列(如
LinkedBlockingQueue无容量限制),该策略永远不会触发 - 存在竞态风险——多个线程同时触发时,可能重复丢弃同一旧任务,需结合业务幂等性设计
除以上四种,还可通过实现RejectedExecutionHandler接口自定义策略,常见做法包括:落库重试、发消息队列、记录带堆栈的日志、触发熔断等。选择策略的核心依据是——任务丢了行不行?谁来承担后果?系统能否感知?









