线程池四大拒绝策略?
线程池的四大拒绝策略是在任务队列满且线程数达到 maximumPoolSize
时处理新任务的方式,定义在 ThreadPoolExecutor
中:
1. AbortPolicy
(中止策略):抛出异常拒绝任务。
2. CallerRunsPolicy
(调用者运行策略):由提交任务的线程执行。
3. DiscardPolicy
(丢弃策略):无声丢弃新任务。
4. DiscardOldestPolicy
(丢弃最旧策略):丢弃队列头部任务,尝试执行新任务。
1. 四大拒绝策略详解
(1) AbortPolicy(中止策略)
- 行为:
- 直接抛出
RejectedExecutionException
,拒绝新任务。 - 源码:
public static class AbortPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() + " rejected");
}
}
- 场景:
- 需要明确失败通知(如关键任务)。
- 示例:
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 1, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.AbortPolicy());
executor.execute(() -> System.out.println("Task 1"));
executor.execute(() -> System.out.println("Task 2")); // 队列满,抛异常
(2) CallerRunsPolicy(调用者运行策略)
- 行为:
- 任务不进入线程池,由提交任务的线程(如主线程)直接执行。
- 源码:
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
- 场景:
- 削峰,防止任务堆积。
- 示例:
- 主线程执行被拒绝的任务,减缓提交速度。
(3) DiscardPolicy(丢弃策略)
- 行为:
- 无声丢弃新任务,不抛异常。
- 源码:
public static class DiscardPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 空实现,丢弃
}
}
- 场景:
- 任务可丢弃(如日志采样)。
- 示例:
- 提交的任务直接忽略,无反馈。
(4) DiscardOldestPolicy(丢弃最旧策略)
- 行为:
- 丢弃队列头部的任务(最早的),尝试执行新任务。
- 源码:
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll(); // 移除头部
e.execute(r); // 再尝试执行
}
}
}
- 场景:
- 优先新任务(如实时数据)。
- 示例:
- 队列满时丢弃旧任务,新任务入队。
2. 使用场景对比
策略 | 行为 | 适用场景 | 优缺点 |
---|---|---|---|
AbortPolicy |
抛异常拒绝 | 需失败通知的关键任务 | 明确反馈,但中断流程 |
CallerRunsPolicy |
调用者执行 | 高负载削峰 | 减缓压力,但阻塞调用者 |
DiscardPolicy |
丢弃新任务 | 可丢弃的非重要任务 | 无反馈,易丢失数据 |
DiscardOldestPolicy |
丢弃旧任务,执行新任务 | 优先最新任务 | 保留新数据,但丢弃旧任务 |
3. 示例代码
ThreadPoolExecutor executor = new ThreadPoolExecutor(
1, 1, 0, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(1),
new ThreadPoolExecutor.CallerRunsPolicy() // 指定策略
);
for (int i = 1; i <= 3; i++) {
int taskId = i;
executor.execute(() -> {
System.out.println("Task " + taskId + " running by " + Thread.currentThread().getName());
try { Thread.sleep(1000); } catch (Exception e) {}
});
}
executor.shutdown();
// 输出:Task 1 线程池执行,Task 2 入队,Task 3 主线程执行
4. 延伸与面试角度
- 自定义策略:
- 实现
RejectedExecutionHandler
:
class CustomPolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
System.out.println("Task rejected, logging...");
}
}
- 与参数关系:
- 拒绝策略与
workQueue
和maximumPoolSize
紧密相关。 - 实际应用:
AbortPolicy
:银行交易。CallerRunsPolicy
:Web 请求限流。- 面试点:
- 问“策略”时,提四种及场景。
- 问“选择”时,提任务重要性。
总结
线程池四大拒绝策略(AbortPolicy
、CallerRunsPolicy
、DiscardPolicy
、DiscardOldestPolicy
)处理队列和线程满时的任务,分别适用于不同优先级和容错需求。面试时,可提代码示例或场景分析,展示理解深度。