多线程篇-线程池使用(springboot)

多线程使用

在实现行车计划排班程序时,遇到了一个问题,问题描述如下:

有一个for循环,循环次数在100以内,一般取20。循环的每一步都比较慢(内套一个循环)。

针对上述问题,首先考虑能不能降低循环次数,答案是不能。然后考虑能不能用多线程优化。

  1. 确定每个线程执行内容

    • 业务内容
  2. 判断是否满足多线程使用条件

    • 一个线程需不需要等待另外一个线程执行结束,答案:否
    • 每个线程有没有共享变量,答案:无
    • 如果有共享变量,涉及不涉及共享变量的读写两个操作,答案:无
  3. 第二步全部满足,则考虑需不需要使用线程池(一般除非是特别简单的需求,否则都建议使用线程池,即:线程池优势)

    • 不必频繁销毁新建线程,提高效率
    • 方便管理线程数目,线程过多会导致内存爆炸
  4. 线程池配置步骤

    • 在springboot的配置文件中添加相关配置(以.yml文件为例)

      # 异步线程配置
      async:
        executor:
          thread:
            core_pool_size: 8 # 配置核心线程数
            max_pool_size: 16 # 配置最大线程数
            queue_capacity: 9999 # 配置队列大小
            name:
              prefix: async-service- # 配置线程池中的线程的名称前缀
      
    • 配置类

      package hisense.apts.common.config;
      
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Value;
      import org.springframework.context.annotation.Bean;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.scheduling.annotation.AsyncConfigurer;
      import org.springframework.scheduling.annotation.EnableAsync;
      import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
      
      import java.util.concurrent.Executor;
      import java.util.concurrent.ThreadPoolExecutor;
      
      /**
       * @author : yuanyu
       * @date : 2023/3/13 16:48
       * @description :
       */
      @Configuration
      @Slf4j
      public class ExecutorConfig{
      
          @Value("${async.executor.thread.core_pool_size}")
          private int corePoolSize;
          @Value("${async.executor.thread.max_pool_size}")
          private int maxPoolSize;
          @Value("${async.executor.thread.queue_capacity}")
          private int queueCapacity;
          @Value("${async.executor.thread.name.prefix}")
          private String namePrefix;
      
          @Bean(name = "asyncServiceExecutor")
          public Executor asyncServiceExecutor() {
              log.info("start asyncServiceExecutor");
              ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
              //配置核心线程数
              executor.setCorePoolSize(corePoolSize);
              //配置最大线程数
              executor.setMaxPoolSize(maxPoolSize);
              //配置队列大小
              executor.setQueueCapacity(queueCapacity);
              //配置线程池中的线程的名称前缀
              executor.setThreadNamePrefix(namePrefix);
      
              // rejection-policy:当pool已经达到max size的时候,如何处理新任务
              // CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
              executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
              //执行初始化
              executor.initialize();
              return executor;
          }
      }
      
      
    • 在springboot启动类中添加@EnableAsync注解

  5. springboot使用线程池

    • 首先把你在多线程中要执行的代码封装到一个方法中
    • 在方法上面添加@Async注解
    • 在调用@Async注解下的方法的时候就可以实现需求了
    • 但是这里有个坑,就是@Async这个注解,它使用是有限制的,所以最好你配置好运行成功之后要验证一下是不是真的是多线程执行的。验证起来很简单,打印当前线程名称即可。
  6. 注意(@Async注解要求)

    • 注解下的方法必须是public的
    • 注解下方法的返回值必须是void或者Future
    • 不可使用static修饰符修饰
    • 对应的位置要添加@EnableAsync注解
    • 调用方与被调用方需在不同的类中
    • 需要使用@Autowired或@Resource等注解自动注入,不能自己手动new对象
    • 在@Async方法上标注@Transactional是没用的,但在@Async方法调用的方法上标注@Transactional是有效的
posted @ 2023-03-20 16:21  盲从者列表  阅读(982)  评论(0)    收藏  举报