线程池拒绝策略详解(5种常见策略)

线程池拒绝策略详解(5种常见策略)-mikechen

线程池拒绝策略主要包含5种,如下图所示,下面重点来详解线程池拒绝策略@mikechen

线程池拒绝策略详解(5种常见策略)-mikechen

第一种:AbortPolicy(默认策略)

当线程池已满且无法继续接受新任务时,会抛出 RejectedExecutionException 异常,拒绝新任务的提交。

如下所示:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.AbortPolicy());

// Submit tasks
executor.submit(() -> System.out.println("Task 1"));
executor.submit(() -> System.out.println("Task 2")); // Will be rejected

这意味着新提交的任务会被丢弃,并且会通知调用者,告知线程池已经达到了最大负荷,无法继续接受任务。

备注:AbortPolicy 是线程池的默认拒绝策略。

 

第二种:CallerRunsPolicy

当线程池已满且无法继续接受新任务时,使用 CallerRunsPolicy 策略会尝试使用提交任务的线程来执行这个任务,而不是立即拒绝任务。

如下所示:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.CallerRunsPolicy());

// Submit tasks
executor.submit(() -> System.out.println("Task 1"));
executor.submit(() -> {
    System.out.println("Task 2 (CallerRunsPolicy)");
    System.out.println("Executed by: " + Thread.currentThread().getName());
});

这种策略可能会影响提交任务的线程,因为它们需要执行额外的任务。

如果提交线程本身已经很繁忙,或者它们是在一个高并发的环境中被不断触发的,那么采用 CallerRunsPolicy 可能会导致提交线程的性能下降。

 

第三种:DiscardPolicy

当线程池已满时,直接丢弃新提交的任务,不会有任何异常抛出,这可能会导致一些任务被忽略。

如下所示:

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.DiscardPolicy());

// Submit tasks
executor.submit(() -> System.out.println("Task 1"));
executor.submit(() -> System.out.println("Task 2")); // Will be discarded

DiscardPolicy 策略会直接丢弃新提交的任务,而不会抛出异常或执行任务。

这种策略适用于一些弱实时性要求的场景,其中丢失一部分任务不会对系统产生严重影响。

比如:日志记录、统计数据等任务可能在高峰期丢失一些数据,但不会对系统的核心功能造成影响。

 

第四种:DiscardOldestPolicy

当线程池已满时,丢弃工作队列中最早的任务,然后尝试将新提交的任务加入队列。

如下所示:

ThreadPoolExecutor executor = new ThreadPoolExecutor
    1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), new ThreadPoolExecutor.DiscardOldestPolicy());

// Submit tasks
executor.submit(() -> System.out.println("Task 1"));
executor.submit(() -> System.out.println("Task 2")); // Task 1 will be discarded

DiscardOldestPolicy 策略的目标是保留最新的任务,这在一些场景中可能是有用的。

比如:如果旧任务的执行结果已经不再重要,而最新的任务更具优先级,那么可以考虑使用这个策略。

 

第五种:自定义策略

你也可以根据应用需求实现自定义的拒绝策略,为此,你需要实现 RejectedExecutionHandler 接口。

如下所示:

class CustomRejectedExecutionHandler implements RejectedExecutionHandler {
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        System.out.println("Custom Rejected Execution: " + r.toString());
    }
}

ThreadPoolExecutor executor = new ThreadPoolExecutor(
    1, 1, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(1), new CustomRejectedExecutionHandler());

// Submit tasks
executor.submit(() -> System.out.println("Task 1"));
executor.submit(() -> System.out.println("Task 2")); // Will trigger custom rejection handler

这些线程池拒绝策略提供了不同的处理方式,可以根据你的应用场景和需求来选择合适的策略。

陈睿mikechen

10年+大厂架构经验,资深技术专家,就职于阿里巴巴、淘宝、百度等一线互联网大厂。

关注「mikechen」公众号,获取更多技术干货!

后台回复面试即可获取《史上最全阿里Java面试题总结》,后台回复架构,即可获取《阿里架构师进阶专题全部合集

评论交流
    说说你的看法