Skip to content

线程池四大拒绝策略?

线程池的四大拒绝策略是在任务队列满且线程数达到 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...");
    }
}
  • 与参数关系
  • 拒绝策略与 workQueuemaximumPoolSize 紧密相关。
  • 实际应用
  • AbortPolicy:银行交易。
  • CallerRunsPolicy:Web 请求限流。
  • 面试点
  • 问“策略”时,提四种及场景。
  • 问“选择”时,提任务重要性。

总结

线程池四大拒绝策略(AbortPolicyCallerRunsPolicyDiscardPolicyDiscardOldestPolicy)处理队列和线程满时的任务,分别适用于不同优先级和容错需求。面试时,可提代码示例或场景分析,展示理解深度。