0


springboot 线程池

为什么要使用线程池

使用

线程池

之后,不需要频繁的去创建和销毁线程(

比如项目中手动创建线程,new Thread 类,我们可以把创建和销毁的线程的过程去掉

),从而让线程得到重复的使用。并且可以对线程进行统一的管理。

在一个网页或应用程序中,每次请求都需要创建新的线程去处理,所以频繁的创建处理这些请求的线程非常消耗资源,为每个请求创建新线程将花费更多的时间,在创建和销毁线程时花费更多的系统资源。因此同时创建太多线程的JVM可能会导致系统内存不足,这就需要限制要创建的线程数,也就是需要使用到线程池。

springboot框架提供了

@Async

注解,帮助我们更方便的将业务逻辑提交到线程池中

异步

执行。

线程池的使用场景

  • 请求量大,任务执行时间短的业务。
  • 无论请求量大小,任务执行时间长的业务。

线程池工作原理

在这里插入图片描述
【图片转自网络】

创建

线程池

时,需要为他指定一个

核心线程数

,以及

最大线程数

,然后还需要给他配置一个

任务队列

当我们把

任务

添加到

线程池

时,首先

线程池

会去判断是否有剩余的

核心线程

,如果有,他就会调用

核心线程

去执行本次任务。如果没有,他会去判断

任务队列

是否已满,如果没满,那他就会把本次

任务

添加到

任务队列

,否则他会去判断线程池中的

最大线程数

是否已满,如果已满,那么他会去执行他的一个

拒绝策略

,否则他会去调用

非核心线程

去执行本次

任务

  • 主线程提交任务到线程池
  • 线程池判断当前线程池的线程数和核心线程数的大小,如果线程数小于核心线程数就新建线程处理任务;否则继续判断当前工作列队是否已满。
  • 如果当前工作队列未满,就将任务放到工作队列中,否则继续判断当前线程池的线程数和最大线程数的大小。
  • 如果当前线程池的线程数小于最大线程数,就新建线程处理请求,否则就执行拒绝策略。

线程池中的拒绝策略

  • AbortPolicy - 抛出RejectedExecutionException异常,终止任务。
  • CallerRunsPolicy - 使用调用线程执行任务。(交由主线程执行。如果执行程序已关闭,则会丢弃该任务
  • DiscardPolicy - 直接丢弃。(抛弃当前任务;会导致被抛弃的任务无法再次被执行
  • DiscardOldestPolicy - 丢弃队列最老任务,然后将本次任务添加到线程池。(抛弃工作队列中旧的任务,将新任务添加进队列;会导致被丢弃的任务无法再次被执行

简单使用

在springboot中为我们提供了线程池类,叫

ThreadPoolTaskExecutor

  • 核心线程数:线程池创建时候初始化的线程数
  • 最大线程数:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
  • 缓冲队列:用来缓冲执行任务的队列

线程依赖于cpu,所以核心线程数量一般设置成cpu个数的两倍,最大线程数一般设置为cpu个数的四倍。

/config/ThreadPoolConfig.java

@ConfigurationpublicclassThreadPoolConfig{// 获取服务器的cpu个数privatestaticfinalintCPU_COUNT=Runtime.getRuntime().availableProcessors();// 获取cpu个数privatestaticfinalintCOUR_SIZE=CPU_COUNT*2;privatestaticfinalintMAX_COUR_SIZE=CPU_COUNT*4;// 接下来配置一个bean,配置线程池。@BeanpublicThreadPoolTaskExecutorthreadPoolTaskExecutor(){ThreadPoolTaskExecutor threadPoolTaskExecutor =newThreadPoolTaskExecutor();
        threadPoolTaskExecutor.setCorePoolSize(COUR_SIZE);// 设置核心线程数
        threadPoolTaskExecutor.setMaxPoolSize(MAX_COUR_SIZE);// 配置最大线程数
        threadPoolTaskExecutor.setQueueCapacity(MAX_COUR_SIZE*4);// 配置队列容量(这里设置成最大线程数的四倍)
        threadPoolTaskExecutor.setThreadNamePrefix("test-thread");// 给线程池设置名称
        threadPoolTaskExecutor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());// 设置任务的拒绝策略return threadPoolTaskExecutor;}}

/controller/ThreadPoolController.java

@RestControllerpublicclassThreadPoolController{privatefinalLogger logger =LoggerFactory.getLogger(ThreadPoolController.class);@ResourceprivateThreadPoolTaskExecutor threadPoolTaskExecutor;@GetMapping("/thread")publicResulttestThread(){
        threadPoolTaskExecutor.execute(()->{Thread.sleep(10000);// 为了演示方便,让变成休眠10秒
            logger.info("执行线程池任务");
            logger.info(Thread.currentThread().getName());//打印线程名称});// 需要传递Runnable对象

        logger.info("主线程名称:{}",Thread.currentThread().getName());//再打印主线程名称returnResult.success("success");}}

启动服务后,访问localhost:8080/thread。然后看控制台,能看出先打印了主线程名称,然后过了10秒,打印了"执行线程池任务"和子线程名称。

主线程名称:http-nio-8002-exec-1
执行线程池任务 // 10秒后...
test-thread1 // 10秒后...

将Service层的服务异步化

/config/ThreadPoolConfig.java

@Configuration@EnableAsync//开启异步调用publicclassThreadPoolConfig{...}

创建controller,开发一个http服务接口,里面会调用service层的服务。将Service层的服务异步化,这样每次调用都会都被提交到线程池异步执行。

/service/TestService.java

publicinterfaceTestService{voidtest();}

/service/TestServiceImpl.java

@ServicepublicclassTestServiceImplimplementsTestService{privatestaticfinalLogger logger =LoggerFactory.getLogger(TestServiceImpl.class);@Override@Async("threadPoolTaskExecutor")// 提交到线程池中去处理publicvoidtest(){
        logger.info("start service");try{Thread.sleep(1000);}catch(Exception e){
            e.printStackTrace();}
        logger.info("end service");}}

/controller/ThreadPoolController.java

@RestControllerpublicclassThreadPoolController{privatestaticfinalLogger logger =LoggerFactory.getLogger(ThreadPoolController.class);@AutowiredprivateTestService testService;@GetMapping("/thread")publicStringtestThread(){
        logger.info("start controller");
        testService.test();
        logger.info("end controller");}}

本文转载自: https://blog.csdn.net/PurineKing/article/details/128776030
版权归原作者 Purine King 所有, 如有侵权,请联系我们删除。

“springboot 线程池”的评论:

还没有评论