线程池的四种拒绝策略及默认策略解析

配资网 阅读: 2024-10-18
后台-插件-广告管理-内容页头部广告(手机)

现在咱们编程圈子里,关于线程池的拒绝机制那可是个关键,但又挺容易被咱们给忽略了。不少程序员可能对这事儿有耳闻,但真要说到怎么用,具体能起到啥作用,可能就一头雾水了。正因为这样,咱们得好好聊聊这个话题。

ThreadPoolExecutor.AbortPolicy:丢弃任务并抛出RejectedExecutionException异常。
ThreadPoolExecutor.DiscardPolicy:丢弃任务,但是不抛出异常。
ThreadPoolExecutor.DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
ThreadPoolExecutor.CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务

线程池拒绝策略的产生背景

/**
 * The default rejected execution handler
 */
private static final RejectedExecutionHandler defaultHandler =
    new AbortPolicy();

在咱们多线程编程这块儿,线程池是个关键玩意儿,它能帮我们高效地管理线程资源,让程序跑得更快。可要是线程池里的任务缓存队列已经挤得满满当当,而且线程数也达到了上限,这时候要是还有新任务来,就得有拒绝策略来处理这些进不去的任务。这就跟酒店一样,房间都住满了,又来客人了,酒店就得按照规矩来处理这种情况。一方面是为了保证整个系统的稳定,另一方面也是为了合理分配资源。虽然线程池能让我们最大限度地利用计算机资源,但资源总是有限的,所以拒绝策略是少不了的。

线上程池那玩意儿,它自个儿就带了个基础的拒绝策略,这玩意儿还挺关键的。咱们开发的时候,要是没特地去调整,线程池就会按着它自个儿定的规矩来办事。这默认的拒绝策略,就是AbortPolicy,啥意思?就是碰到任务太多的时候,它直接把任务给扔了,然后还得抛个RejectedExecutionException的异常出来。就像是个酒店,你说它不乐意再接待客人了,来了超量的客人,直接说不行,然后还得跟客人解释为啥不能接待。咱们这事儿,用代码一验证,还真是这么个理儿。咱们搞个普通的线程池,不特意设置拒绝策略,只限定一下线程队列的最大容量,那在实践中,它表现出来的就是AbortPolicy这策略。知道这个默认策略,对咱们在编程初期理解线程池的管理机制,那可有大帮助。

public class ThreadPoolTest {
    public static void main(String[] args) {
        BlockingQueue queue = new ArrayBlockingQueue<>(100);
        ThreadFactory factory = r -> new Thread(r, "test-thread-pool");
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 5,
                0L, TimeUnit.SECONDS, queue, factory);
        while (true) {
            executor.submit(() -> {
                try {
                    System.out.println(queue.size());
                    Thread.sleep(10000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            });
        }
    }
}

如何设置自己所需的拒绝策略

策略圈_策略圈_策略圈

在这里插入图片描述

在实际的工作场景里,那线程池自带的拒绝处理方式可能不太合用。这会儿,咱们得根据具体情况来调整设置。要是想改线程池的拒绝策略,得用ThreadPoolExecutor的扩展构造方法来操作。尤其是在用spring框架搞开发的时候,设置拒绝策略还有个更方便的方法。用org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor来搭建线程池,通过它的setRejectedExecutionHandler方法就能简单搞定拒绝策略,就跟酒店根据不同时段(比如旺季、淡季、临时活动啥的)调整接待规定一样,都是为了更好地应对实际情况。

AbortPolicy拒绝策略深入分析

线程池里头默认的拒绝机制,AbortPolicy这玩意儿有它自己的脾气。一旦任务塞不进去了,它就直接来个异常抛出,这么一操作能马上给咱们反馈程序的运行情况。尤其是一些关键的业务操作,这招挺管用的。比如说金融转账,要是人太多系统承受不住,这异常就能迅速帮我们找到问题所在。但话说回来,这策略也有点小问题,就是线程队列满了之后,新来的任务不光是被扔了,还悄无声息地被扔了,这可能导致我们很难彻底弄清楚系统出了啥问题。就像酒店把客人拒之门外,都不说为啥,这会影响人家对酒店服务水平的判断一样。

在这里插入图片描述

ThreadPoolExecutor中的丢弃最早策略解析

策略圈_策略圈_策略圈

@Configuration
public class TaskExecutorConfig implements AsyncConfigurer {
    /**
     * Set the ThreadPoolExecutor's core pool size.
     */
    private static final int CORE_POOL_SIZE = 5;
    /**
     * Set the ThreadPoolExecutor's maximum pool size.
     */
    private static final int MAX_POOL_SIZE = 5;
    /**
     * Set the capacity for the ThreadPoolExecutor's BlockingQueue.
     */
    private static final int QUEUE_CAPACITY = 1000;
    /**
     * 通过重写getAsyncExecutor方法,制定默认的任务执行由该方法产生
     * 

* 配置类实现AsyncConfigurer接口并重写getAsyncExcutor方法,并返回一个ThreadPoolTaskExevutor * 这样我们就获得了一个基于线程池的TaskExecutor */ @Override public Executor getAsyncExecutor() { ThreadPoolTaskExecutor taskExecutor = new ThreadPoolTaskExecutor(); taskExecutor.setCorePoolSize(CORE_POOL_SIZE); taskExecutor.setMaxPoolSize(MAX_POOL_SIZE); taskExecutor.setQueueCapacity(QUEUE_CAPACITY); taskExecutor.initialize(); taskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy()); return taskExecutor; } }

这个策略挺独到,它会把队首的任务给扔掉,再把那些被拒的任务重新来过。这时候,咱们开发者得好好想想,看业务规则是不是允许把旧任务给踢掉。任务要是被拒了,负责提交的那个线程就会直接给它开绿灯。你从代码里头检查一下,把队列的最大数改了,再看看哪个线程在干活,比如说是主线程main,你就能发现它也掺和进来了,这就证明了在这种策略下,执行任务的机制就是让调用线程来干。在一些需求变化多端,对任务完成速度有特别要求的场合,这招儿可能就派上用场了。

根据业务场景择取合适的拒绝策略

A handler for rejected tasks that throws a {@code RejectedExecutionException}.

在实际的开发实践中,咱们得面对各种各样复杂的业务情况,这时候选啥样的线程池拒绝方案,那可真是个挺头疼的问题,但又不得不去解决。每种方案都有它自己的长处和短处,所以说不能随便说哪个好或者不好。咱们得根据业务的具体情况,比如任务的重要程度、优先级,还有对任务丢失的容忍度这些因素,来全面考虑。就像酒店会根据住客的类型(比如旅游团、商务人士)等因素来制定不同的接待方案一样。比如说,对于那些对数据准确性和完整性要求极高的应用,AbortPolicy可能是个不错的选择;而对于那些以数据分析为主,对部分旧数据不太在意的系统,DiscardOldestPolicy可能更能满足需求。

我想问问大家,在你们做项目的时候,是不是遇到过因为选错了线程池的拒绝策略而碰到的麻烦事儿?希望你们能在评论区说出来,顺便如果觉得这篇文章帮到了你们,点个赞和转发一下呗。

A handler for rejected tasks that silently discards therejected task.

本文 融资融券杠杆炒股 原创,转载保留链接!网址:http://www.cdkaixi.cn/zmt/421.html

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

后台-插件-广告管理-内容页尾部广告(手机)
关注我们

扫一扫关注我们,了解最新精彩内容

搜索