拒绝策略由线程池构造时指定的rejectedexecutionhandler实现类决定,java提供abortpolicy、callerrunspolicy、discardpolicy、discardoldestpolicy四种内置策略,也可自定义实现。

当线程池的核心线程全部忙碌,且工作队列也已满时,新提交的任务会触发拒绝策略(RejectedExecutionHandler)。
拒绝策略由什么决定
拒绝行为不是自动发生的,而是由线程池构造时指定的 RejectedExecutionHandler 实现类控制。Java 提供了 4 种内置策略,也可自定义。
四种内置拒绝策略及适用场景
-
AbortPolicy(默认):直接抛出
RejectedExecutionException异常。适合不允许丢失任务、希望快速暴露问题的场景。 - CallerRunsPolicy:让调用线程(即 submit 或 execute 的线程)自己执行该任务。可缓解压力,但可能拖慢调用方,适用于对延迟敏感度较低、允许任务“回退”执行的场景。
- DiscardPolicy:静默丢弃任务,不抛异常也不通知。适合可容忍少量任务丢失的场景,比如监控埋点、日志上报等非关键操作。
- DiscardOldestPolicy:丢弃队列头部(最早入队)的任务,再尝试重新提交当前任务。适合希望尽可能保留最新任务的场景,但要注意队列是否支持高效移除头结点(如 LinkedBlockingQueue 支持,ArrayBlockingQueue 也支持,但性能略低)。
如何设置和自定义拒绝策略
可通过 ThreadPoolExecutor 构造器传入 handler 参数,或使用 setRejectedExecutionHandler() 动态修改:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 5, 60L, TimeUnit.SECONDS,
new LinkedBlockingQueue(10),
new ThreadPoolExecutor.CallerRunsPolicy() // 指定策略
);
自定义策略只需实现 RejectedExecutionHandler 接口,重写 rejectedExecution(Runnable r, ThreadPoolExecutor executor) 方法。例如记录日志、发告警、降级处理或存入重试队列。
关键细节注意
- 拒绝只发生在 核心线程忙 + 队列满 + 无法扩容到最大线程数(或已达最大线程数仍无法接纳)时;
- 如果使用无界队列(如
LinkedBlockingQueue无参构造),除非设置了最大线程数且活跃线程已达上限,否则一般不会触发拒绝(因为队列永不满); - 使用有界队列时,务必配合合理的拒绝策略,否则任务可能意外丢失或阻塞调用方;
- 某些第三方线程池封装(如 Spring 的
ThreadPoolTaskExecutor)默认使用AbortPolicy,但可通过setRejectedExecutionHandler替换。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











