自定义 RejectedExecutionHandler 的核心是实现接口并注入 ThreadPoolExecutor 构造过程,仅在有界队列满且线程数达 maximumPoolSize 时触发;需避免递归调用 submit/execute,常见策略包括可观测、补偿和调用方感知型。

Java 中自定义 RejectedExecutionHandler 的核心,是实现接口并注入到 ThreadPoolExecutor 构造过程里——它不是补救手段,而是系统水位超限时的主动响应逻辑。
明确触发条件再动手
拒绝策略只在两个条件**同时成立**时才生效:
- 工作队列已满,且必须是有界队列(如
ArrayBlockingQueue(200));用LinkedBlockingQueue默认无界,任务会无限堆积,OOM 风险远高于触发拒绝 - 当前线程数已达
maximumPoolSize,包括核心与非核心线程
所以先确认你用的是有界队列,并设置合理容量(例如按峰值 QPS × 平均处理耗时 × 安全系数估算),否则自定义 Handler 永远不会被调用。
实现 RejectedExecutionHandler 接口
只需重写 rejectedExecution(Runnable r, ThreadPoolExecutor executor) 方法:
Java项目代码review工具。分析Git变更+完整调用链路上下文,推断业务需求,进行多维度评分和分类汇总,生成完整PRD文档。包含细粒度Java代码审查清单(Null安全、异常处理、Streams、并发、equals/hashCode、资源管理、API设计、性能、MyBatis/ORM、事务边界、SQL/DD...
立即学习“Java免费学习笔记(深入)”;
-
r是被拒的任务,可能是普通Runnable或封装后的FutureTask -
executor可用来获取实时状态:getActiveCount()、getQueue().size()、getMaximumPoolSize()等 - 方法内可记录日志、发消息、落盘暂存,但不能调用
executor.submit()或execute(),否则可能递归触发拒绝甚至死锁
常见实用策略类型
根据业务目标选择主逻辑方向:
- 可观测型:记录关键上下文(任务类名、队列大小、活跃线程数),加日志限流(避免高频拒绝打爆磁盘或 I/O)
- 补偿型:异步发往 Kafka 或 RocketMQ 备份队列(带超时与降级,失败时 fallback 到本地文件暂存)
-
调用方感知型:抛出自定义异常(如
TaskRejectedException),由上游捕获后走降级流程,不静默吞任务
正确注册到线程池
必须在构建线程池时传入,后期无法替换:
- 使用
ThreadPoolExecutor构造器,第 8 个参数传入自定义实例 - 不要用
Executors.newFixedThreadPool()等工具类,它们内部固定使用AbortPolicy,无法更换 - 注意:只有
execute()和submit()会触发该策略;invokeAll()等批量方法也适用

















