当线程池饱和时,新任务触发拒绝策略;Java提供四种默认策略,但业务常需自定义RejectionExecutionHandler实现精细化控制,如日志告警、异步重试或同步降级。

当线程池的队列已满且所有核心与最大线程都在忙碌时,新提交的任务会触发拒绝策略。Java 默认提供四种内置策略(如 AbortPolicy、CallerRunsPolicy 等),但业务常需更精细的控制——比如记录日志、降级处理、异步重试或通知监控系统。自定义拒绝策略的核心是实现 RejectedExecutionHandler 接口。
实现 RejectedExecutionHandler 接口
你需要创建一个类,实现 RejectedExecutionHandler,并重写 rejectedExecution(Runnable r, ThreadPoolExecutor executor) 方法:
- 参数
r是被拒绝的任务(可能为null,例如调用shutdownNow()后) - 参数
executor是当前线程池实例,可用于获取状态(如getQueue().size()、getActiveCount()、isShutdown()等) - 该方法在调用者线程中执行(即提交任务的线程),不是在线程池内运行
常见自定义场景与示例
1. 记录详细拒绝日志 + 上报告警
适合对稳定性要求高的服务,便于事后分析压测瓶颈或突发流量:
public class AlertingRejectHandler implements RejectedExecutionHandler {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final AlertClient alertClient;
public AlertingRejectHandler(AlertClient alertClient) {
this.alertClient = alertClient;
}
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
String taskName = (r instanceof FutureTask) ?
((FutureTask<?>) r).toString() : r.getClass().getName();
logger.warn("Task rejected: {}, pool=[active={}, queue={}/{}], core={} max={}",
taskName,
executor.getActiveCount(),
executor.getQueue().size(), executor.getQueue().remainingCapacity(),
executor.getCorePoolSize(), executor.getMaximumPoolSize());
alertClient.send("线程池任务被拒绝", "pool=" + executor.toString());
}
}
2. 异步缓冲 + 本地重试(带限流)
适用于允许轻微延迟、但不可丢弃任务的场景(如日志聚合、埋点上报):
- 用一个带容量限制的内存队列(如
ConcurrentLinkedQueue)暂存被拒任务 - 启动一个单独的守护线程,定期尝试重新提交(需判断线程池是否仍可用)
- 加入简单计数器防止缓冲区无限膨胀
3. 优雅降级:转同步执行或返回默认值
对非关键路径任务(如推荐结果缓存刷新),可回退到调用方线程直接执行:
public class SyncFallbackHandler implements RejectedExecutionHandler {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
if (!executor.isShutdown()) {
try {
r.run(); // 在当前线程同步执行(注意:可能阻塞调用方)
} catch (Throwable t) {
// 记录异常,避免影响主流程
logger.error("Sync fallback failed", t);
}
}
}
}
注册自定义策略到线程池
构造 ThreadPoolExecutor 时传入即可;若使用 Executors 工具类(不推荐生产环境),需手动包装:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4, 8,
60L, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(100),
new CustomThreadFactory(),
new AlertingRejectHandler(alertClient) // ← 自定义策略
);
注意:ScheduledThreadPoolExecutor 不支持自定义拒绝策略(其 setRejectedExecutionHandler 是空实现),如需控制调度任务拒绝行为,应自行封装调度逻辑。
立即学习“Java免费学习笔记(深入)”;
避坑提醒
- 拒绝策略方法中避免长时间阻塞(如同步 IO、锁竞争),否则会拖慢任务提交方
- 不要在该方法里再次调用
execute()或submit()原线程池,易引发递归拒绝或死锁 - 若任务实现了
RunnableScheduledFuture(如ScheduledFutureTask),注意类型转换安全 - 测试时模拟饱和:可设极小队列(如
new ArrayBlockingQueue(1))+ 固定线程数 + 快速提交大量任务
自定义拒绝策略本质是把“系统过载”这一事实显式暴露出来,并赋予你按业务语义做决策的能力。它不是兜底万能方案,而是熔断、降级、可观测性体系中的关键一环。


















