• springBoot 的默认线程池-ThreadPoolTaskExecutor


    前言

      如果您觉得有用的话,记得给博主点个赞,评论,收藏一键三连啊,写作不易啊^ _ ^。
      而且听说点赞的人每天的运气都不会太差,实在白嫖的话,那欢迎常来啊!!!


    springBoot 的默认线程池

    01 ThreadPoolTaskExecutor是什么?

    hreadPoolTaskExecutor是spring core包中的,
    ThreadPoolTaskExecutor是对ThreadPoolExecutor进行了封装,
    是sring为我们提供的线程池类。

    02 实战

    02::01 配置
    
    import com.google.common.util.concurrent.ThreadFactoryBuilder;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
    
    import java.util.concurrent.ThreadPoolExecutor;
    
    /**
     * @author yangzhenyu
     * @version 1.0
     * @description: springBoot 默认线程池
     * @date 2022/9/13 16:56
     */
    @Configuration
    @EnableAsync
    public class ThreadPoolTaskExecutorConfig {
        @Bean("poolTaskExecutor")
        public ThreadPoolTaskExecutor taskExecutor() {
            ThreadPoolTaskExecutor  threadPoolExecutor = new ThreadPoolTaskExecutor();
            threadPoolExecutor = new ThreadPoolTaskExecutor();
            //核心线程数
            threadPoolExecutor.setCorePoolSize(5);
            //最大线程数
            threadPoolExecutor.setMaxPoolSize(5);
            //允许线程最大空闲时间、默认为秒
            threadPoolExecutor.setKeepAliveSeconds(5);
            //缓存队列大小
            threadPoolExecutor.setQueueCapacity(5000);
            //线程池对拒绝任务的处理策略 - 始终抛出RejectedExecutionException
            threadPoolExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.AbortPolicy());
            //线程池名前缀
            //threadPoolExecutor.setThreadNamePrefix(THREAD_NAME_PREFIX);
            threadPoolExecutor.setThreadFactory(new ThreadFactoryBuilder().setNameFormat("yzy-Async-%d").build());
            /**
            * taskDecorator主要是对Runnable任务装饰一下, 在任务执行时完成异常日志打印、ThreadLocal清理等功能
             * 但是对Callable任务(由submit()方法提交的任务),这个taskDecorator虽然也能装饰,但是并不能捕获异常,
             * 因为类似FutureTask的run方法内部自己补获了异常,不会抛出到afterExecute方法中
            */
            // 增加 TaskDecorator 属性的配置,解决多线程场景下,获取不到request上下文的问题
            threadPoolExecutor.setTaskDecorator(new MyDecorator());
            threadPoolExecutor.initialize();
            return threadPoolExecutor;
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47

    当线程池的任务缓存队列已满并且线程池中的线程数目达到maximumPoolSize,如果还有任务到来就会采取任务拒绝策略, rejectedExecutionHandler 字段用于配置拒绝策略,常用的拒绝策略如下:

    • AbortPolicy:用于被拒绝任务的处理程序,它将抛出 RejectedExecutionException。
    • CallerRunsPolicy:用于被拒绝任务的处理程序,它直接在 execute 方法的调用线程中运行被拒绝的任务。
    • DiscardOldestPolicy:用于被拒绝任务的处理程序,它放弃最旧的未处理请求,然后重试 execute。
    • DiscardPolicy:用于被拒绝任务的处理程序,默认情况下它将丢弃被拒绝的任务。
    
    import org.slf4j.MDC;
    import org.springframework.core.task.TaskDecorator;
    import org.springframework.web.context.request.RequestAttributes;
    import org.springframework.web.context.request.RequestContextHolder;
    
    import java.util.Map;
    
    /**
     * @author yangzhenyu
     * @version 1.0
     * @description:
     * @date 2022/9/13 18:35
     */
    public class MyDecorator implements TaskDecorator {
    
        @Override
        public Runnable decorate(Runnable runnable) {
            RequestAttributes context = RequestContextHolder.currentRequestAttributes();
            Map<String,String> previous = MDC.getCopyOfContextMap();
            return () -> {
                try {
                    RequestContextHolder.setRequestAttributes(context);
                    if (null != previous){
                        MDC.setContextMap(previous);
                    }
                    runnable.run();
                } finally {
                    RequestContextHolder.resetRequestAttributes();
                    MDC.clear();
                }
            };
        }
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    02::02 使用

    我们这里用单元测试来进行测试。

    注解式使用:
    在使用多线程方法上标注@Async时表明调用的线程池

    package com.yzy.task;
    
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.stereotype.Component;
    
    /**
     * @author yangzhenyu
     * @version 1.0
     * @description:
     * @date 2022/9/13 17:11
     */
    @Component
    @Slf4j
    public class Tast {
        //在使用多线程方法上标注@Async时表明调用的线程池
        //注意:一定要在Spring的环境下
        @Async("poolTaskExecutor")
        public  void  testTast() throws InterruptedException {
            log.info("=========== hello ==============");
        }
    
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    注意:一定要在Spring的环境下

    测试:

    
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = ThymeleafDemo.class)
    @Slf4j
    public class TastTest{
    
        // 注入ThreadPoolTaskExecutor
        @Resource
        private Tast tast;
    
        //注解式实现
        @Test
        public void ThreadTest_01() throws InterruptedException {
            log.info("测试开始>>>");
            for (int i=0;i<10;i++) {
                tast.testTast();
            }
            log.info("测试结束>>>");
    
        }
       
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述

    创建并执行线程方式:

    
    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = ThymeleafDemo.class)
    @Slf4j
    public class TastTest{
    
    
        @Qualifier("poolTaskExecutor")
        @Resource
        private ThreadPoolTaskExecutor threadPoolTaskExecutor;
    
        //创建并执行线程方式
        @Test
        public void ThreadTest_02()   {
            log.info("测试开始>>>");
            MDC.put("yzy", "yangzhenyu");
            for (int i=0;i<10;i++) {
                //lambda表达式
                threadPoolTaskExecutor.execute(()->{
                        System.out.printf("lambda-当前线程%s%n",Thread.currentThread().getName());
                });
            }
            log.info("测试结束>>>");
    
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    在这里插入图片描述

  • 相关阅读:
    搞定面试官 - 可以介绍一下在 MySQL 中你平时是怎么使用 COUNT() 的嘛?
    u盘文件损坏怎么恢复数据 U盘插上就让格式化是坏了吗?
    进口气动不锈钢隔膜泵的选型说明
    常写的页面(备份)
    mysql sql解释执行优化
    数据结构与算法-图
    上传项目代码到github
    手把手写深度学习(16):用CILP预训练模型搭建图文检索系统/以图搜图/关键词检索系统
    Linux------权限篇2)
    一文让你彻底了解Linux内核文件系统(大总结)
  • 原文地址:https://blog.csdn.net/weixin_38316697/article/details/126856860