在 Java 的 ThreadPoolExecutor
中,当线程池的 线程数量达到最大值,且 任务队列已满 时,新的任务将被拒绝。为了应对这种情况,Java 提供了 四种拒绝策略,用于处理被拒绝的任务。
AbortPolicy(默认策略)
-
行为:直接抛出
RejectedExecutionException
。 -
特点:
-
默认策略
-
任务无法提交时,明确通知调用方
-
-
示例代码:
ThreadPoolExecutor executor = new ThreadPoolExecutor(
2, 4, 60, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2),
new ThreadPoolExecutor.AbortPolicy()
);
-
适用场景:任务必须执行,否则抛异常提醒。
CallerRunsPolicy
-
行为:由调用线程执行任务。
-
特点:
-
不抛异常
-
对任务进行“限流”,减缓线程池压力
-
调用线程可能被阻塞
-
-
示例代码:
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
-
适用场景:需要保证任务最终执行,同时防止线程池过载。
DiscardPolicy
-
行为:直接丢弃被拒绝的任务,不抛异常。
-
特点:
-
简单粗暴
-
可能丢失任务
-
-
示例代码:
-
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardPolicy());
-
适用场景:任务可以丢失,不要求每个任务都执行。
DiscardOldestPolicy
-
行为:丢弃队列中最旧的任务,再尝试提交新任务。
-
特点:
-
保证新任务有机会执行
-
可能丢失老任务
-
-
示例代码:
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
-
适用场景:队列中老任务可舍弃,优先保证新任务执行。
总结表格
策略 | 行为描述 | 使用场景 |
---|---|---|
AbortPolicy | 抛异常 | 必须保证任务执行 |
CallerRunsPolicy | 调用线程执行任务 | 限流,避免抛异常 |
DiscardPolicy | 直接丢弃任务 | 任务可丢失 |
DiscardOldestPolicy | 丢弃最旧任务,再提交新任务 | 老任务可舍弃,优先新任务执行 |
💡 Tips:
如果任务不可丢失,通常使用 AbortPolicy 或 CallerRunsPolicy。
如果任务可以舍弃,DiscardPolicy 或 DiscardOldestPolicy 可以减少系统压力。