Java线程池在关闭或队列满且线程数达maximumPoolSize时,通过RejectedExecutionHandler处理超量任务;内置四种策略:AbortPolicy抛异常、CallerRunsPolicy由调用线程执行、DiscardPolicy静默丢弃、DiscardOldestPolicy丢弃最旧任务;自定义策略需实现接口并避免耗时操作,配合监控及时告警。

Java 中线程池对超出队列容量的提交任务,会通过拒绝策略(RejectedExecutionHandler)来统一处理。核心在于:当线程池已关闭,或线程数已达 maximumPoolSize 且工作队列已满时,新提交的任务会被拒绝,此时由你指定的拒绝策略决定如何应对。
四种内置拒绝策略及适用场景
ThreadPoolExecutor 提供了四个静态内部类实现,直接传入构造函数即可:
-
AbortPolicy(默认):抛出
RejectedExecutionException。适合不允许丢任务、需快速暴露问题的场景,例如金融交易类系统。 -
CallerRunsPolicy:由调用
execute()的线程(即主线程)直接执行该任务。可减缓提交速度,避免雪崩,适合任务可延迟执行且调用方能承受短时阻塞的情况。 - DiscardPolicy:静默丢弃任务,不抛异常也不通知。适用于允许丢失、实时性要求低的任务,如日志采集中的非关键埋点。
- DiscardOldestPolicy:丢弃队列头部(最旧)的任务,再尝试重新提交当前任务。适合希望尽量保留最新任务的场景,比如实时行情推送。
自定义拒绝策略:记录日志 + 降级处理
实际项目中常需更精细控制,例如记录被拒任务详情、触发告警、写入死信队列等。只需实现 RejectedExecutionHandler 接口:
当用户要求为 Java 代码添加注释、修改注释、审查注释、整理注释格式,或要求按照代码注释规范处理 Java 文件时,使用本技能。本技能用于统一生成和维护 Java 类注释模板、按 Git 对比 release 判断版本号、补充每行代码上方中文块注释、调整注释空行规则,并保持 Java 文件 UTF-8 无 BOM 编码。典型触发场景包括:补充类注释、更新 @version、检查 @author 来源、整理行尾注释、把注释放到代码上一行、检查注释是否符合规范、构建前检查 Java 注释风格。
public class LoggingRejectHandler implements RejectedExecutionHandler {
private static final Logger log = LoggerFactory.getLogger(LoggingRejectHandler.class);
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
String taskInfo = r instanceof FutureTask ?
((FutureTask<?>) r).toString() : r.toString();
log.warn("Task rejected: {}, pool: [active={}, queue={}, core={}, max={}]",
taskInfo,
executor.getActiveCount(),
executor.getQueue().size(),
executor.getCorePoolSize(),
executor.getMaximumPoolSize());
// 可选:将任务转存到本地文件或 Kafka 死信主题
// saveToDeadLetter(r);
}
}
使用时传入线程池构造器:
立即学习“Java免费学习笔记(深入)”;
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(10),
new LoggingRejectHandler()
);
关键注意事项
- 拒绝策略只在
execute()方法中触发;submit()底层也调用execute(),所以同样生效。 - 若使用无界队列(如
LinkedBlockingQueue无参构造),队列永远不会满,除非线程池已关闭,否则不会触发拒绝策略——这点极易被忽略。 - 慎用
CallerRunsPolicy在高并发 Web 请求线程中,可能导致 Tomcat 线程阻塞,影响整体吞吐。 - 自定义策略里避免做耗时操作(如远程调用、磁盘写入),否则会拖慢
execute()调用方,甚至引发连锁拒绝。
配合监控及时发现拒绝行为
仅靠策略不够,还需可观测性。可通过以下方式主动感知:
- 重写
rejectedExecution方法时,用 Prometheus Counter 计数,配置告警阈值; - 定期检查
executor.getRejectedExecutionHandler()是否被意外替换; - 结合 JVM 线程数、队列长度、活跃线程数等指标,绘制趋势图,定位突增源头。

















