# Java 线程池的拒绝策略

当线程池无法处理新提交的任务时,Java提供了四种默认的拒绝策略(RejectedExecutionHandler),可以根据应用场景选择合适的策略来处理此类情况。线程池在以下两种情况下会触发拒绝策略:

  1. 任务队列已满。
  2. 线程池中的线程数量已经达到了maximumPoolSize,无法再创建新的线程处理任务。

# 1. 四种默认拒绝策略

# 1.1 AbortPolicy(默认策略)

  • 作用:直接抛出RejectedExecutionException异常,拒绝处理新任务。
  • 适用场景:当任务的执行是不可或缺的,并且程序希望立即发现任务被拒绝的情况时使用。
RejectedExecutionHandler abortPolicy = new ThreadPoolExecutor.AbortPolicy();
1

# 1.2 CallerRunsPolicy

  • 作用:当线程池无法处理新任务时,由提交任务的线程(调用者线程)来执行该任务。这种策略既不会抛弃任务,也不会抛出异常。
  • 适用场景:适用于任务量偶尔超出线程池负荷的场景,能降低任务丢失的风险,但可能会降低提交任务的线程处理其他任务的能力。
RejectedExecutionHandler callerRunsPolicy = new ThreadPoolExecutor.CallerRunsPolicy();
1

# 1.3 DiscardPolicy

  • 作用:默默丢弃无法处理的任务,不抛出任何异常。
  • 适用场景:适用于对任务的丢弃不敏感,或允许在高负载情况下自动抛弃新任务的场景。
RejectedExecutionHandler discardPolicy = new ThreadPoolExecutor.DiscardPolicy();
1

# 1.4 DiscardOldestPolicy

  • 作用:丢弃任务队列中等待时间最长的任务,然后尝试将新任务加入队列。
  • 适用场景:适合对最新任务优先级较高的场景。通过丢弃较老的任务来腾出空间处理新任务。
RejectedExecutionHandler discardOldestPolicy = new ThreadPoolExecutor.DiscardOldestPolicy();
1

# 2. 自定义拒绝策略

除了上述四种默认策略,Java允许开发者通过实现RejectedExecutionHandler接口来自定义拒绝策略,以应对更复杂的业务场景。

# 2.1 自定义拒绝策略示例

下面是一个自定义拒绝策略的例子,当任务被拒绝时,记录日志并重新尝试提交任务。

public class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        // 记录被拒绝的任务
        System.out.println("Task " + r.toString() + " rejected from " + executor.toString());
        
        // 重新提交任务或执行其他处理
        // 可以根据业务需求决定是否重新执行任务
    }
}

// 在创建线程池时指定自定义拒绝策略
ExecutorService executorService = new ThreadPoolExecutor(
    2, 4, 60, TimeUnit.SECONDS,
    new ArrayBlockingQueue<>(10),
    new CustomRejectedExecutionHandler()
);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 3. 选择拒绝策略的注意事项

  1. 系统稳定性AbortPolicy会直接抛出异常,适合对系统稳定性要求较高的场景;而DiscardPolicyDiscardOldestPolicy可能导致任务丢失,适合对稳定性要求不高的场景。
  2. 任务优先级DiscardOldestPolicy适用于对最新任务优先级较高的场景,而CallerRunsPolicy可以确保任务不会丢失,但可能会降低调用者线程的效率。
  3. 性能与资源:对于高并发和大负载场景,需要选择适当的拒绝策略以防止系统过载,同时根据业务逻辑决定任务是否可以丢弃或延迟执行。

# 4. 总结

Java线程池提供了四种默认的拒绝策略,分别是:

  • AbortPolicy:抛出异常。
  • CallerRunsPolicy:提交任务的线程自己执行任务。
  • DiscardPolicy:丢弃无法执行的任务。
  • DiscardOldestPolicy:丢弃最老的任务。

根据具体业务需求和系统资源限制,合理选择和配置拒绝策略,以确保系统在高并发场景下的稳定性和任务的高效处理。

备案号:粤ICP备2023124211号-1
Copyright © 2023-2024 StarChenTech All Rights Reserved.