java自定义线程池拒绝策略需实现rejectedexecutionhandler接口,在maximumpoolsize已达、工作队列满且新任务提交时触发;jdk提供abortpolicy、callerrunspolicy、discardpolicy、discardoldestpolicy四种内置策略,自定义策略须避免耗时操作与死循环。

Java 自定义线程池实现拒绝策略,核心在于传入一个实现了 RejectedExecutionHandler 接口的对象。它不是“重写线程池”,而是在线程池构造时指定处理逻辑,当任务无法被接收(队列满 + 线程数已达最大)时触发。
理解拒绝策略的触发时机
拒绝策略只在以下条件**同时满足**时执行:
- 线程池中线程数已达
maximumPoolSize - 工作队列已满(如
ArrayBlockingQueue达到 capacity) - 又有新任务提交(调用
execute())
此时线程池无法接纳任务,就会调用你设置的拒绝策略处理器。
内置拒绝策略及适用场景
JDK 提供了四种常用实现,可直接复用:
-
AbortPolicy(默认):抛出
RejectedExecutionException,适合容错要求高、需快速暴露问题的场景 - CallerRunsPolicy:由提交任务的线程(如主线程)自己执行该任务,可缓解压力但可能阻塞调用方
- DiscardPolicy:静默丢弃任务,不报错,适合允许丢失、吞吐优先的场景(如日志上报)
- DiscardOldestPolicy:丢弃队列头部最老的任务,再尝试提交当前任务;适合希望尽量保留最新任务的场景
自定义拒绝策略(实现 RejectedExecutionHandler)
只需实现接口并重写 rejectedExecution(Runnable r, ThreadPoolExecutor executor) 方法:
例如:记录日志 + 落盘暂存 + 发送告警
public class LoggingAndStorePolicy implements RejectedExecutionHandler {
private final BlockingQueue<runnable> backupQueue = new LinkedBlockingDeque();
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
// 1. 记录警告日志
System.err.println("Task rejected: " + r + ", pool: " + executor);
// 2. 尝试存入本地备份队列(注意容量控制)
if (!backupQueue.offer(r)) {
System.err.println("Backup queue full, dropping task: " + r);
}
// 3. 可选:触发异步告警(如发短信、写监控指标)
AlertUtils.sendAlert("ThreadPoolOverload", executor.getPoolSize());
}
}</runnable>
使用方式:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue(10),
new LoggingAndStorePolicy() // ← 传入自定义策略
);
注意事项和常见误区
- 拒绝策略方法运行在提交线程中(非线程池线程),避免耗时操作(如远程调用、大对象序列化)
- 不要在策略里再调用
executor.execute(r),极易引发死循环或栈溢出 - 若需重试,建议交由外部补偿机制(如定时扫描备份队列)而非在拒绝时同步重试
-
submit()方法同样会触发拒绝策略,因为最终也会调用execute()
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











