• Spring Boot使用@Async实现异步调用:自定义线程池


    定义线程池

    第一步,先定义一个线程池,比如:

    @Configuration
    public class PoolConfig {
    
        @Bean("testExecutor")
        public Executor testExecutor() {
            ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
            executor.setCorePoolSize(10);
            executor.setMaxPoolSize(20);
            executor.setQueueCapacity(200);
            executor.setKeepAliveSeconds(60);
            executor.setThreadNamePrefix("testExecutor-");
            executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
            return executor;
        }
    }
    

    @EnableAsync这个注解如果在启动类已经添加过,就无需再次添加.

    上面我们通过使用ThreadPoolTaskExecutor创建了一个线程池,同时设置了以下这些参数:

    • 核心线程数10:线程池创建时候初始化的线程数
    • 最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
    • 缓冲队列200:用来缓冲执行任务的队列
    • 允许线程的空闲时间60秒:当超过了核心线程出之外的线程在空闲时间到达之后会被销毁
    • 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
    • 线程池对拒绝任务的处理策略:这里采用了CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务

    使用线程池

    在定义了线程池之后,我们如何让异步调用的执行任务使用这个线程池中的资源来运行呢?方法非常简单,我们只需要在@Async注解中指定线程池名即可,比如:

    @Slf4j
    @Service
    public class TestMethod {
    
        public static Random random = new Random();
    
        @Async("testExecutor")
        public void one() throws Exception {
            log.info("第一个");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成一,耗时:" + (end - start) + "毫秒");
        }
    
        @Async("testExecutor")
        public void two() throws Exception {
            log.info("第二个");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成二,耗时:" + (end - start) + "毫秒");
        }
    
        @Async("testExecutor")
        public void three() throws Exception {
            log.info("第三个");
            long start = System.currentTimeMillis();
            Thread.sleep(random.nextInt(10000));
            long end = System.currentTimeMillis();
            log.info("完成三,耗时:" + (end - start) + "毫秒");
        }
    
    }
    

    单元测试

    最后,我们来写个单元测试来验证一下

    @RunWith(SpringJUnit4ClassRunner.class)
    @SpringBootTest
    public class TestApplicationTests {
    
        @Autowired
        private TestMethod testMethod;
    
        @Test
        public void test() throws Exception {
    
            testMethod.one();
            testMethod.two();
            testMethod.three();
    
            Thread.currentThread().join();
        }
    
    }
    

    执行上面的单元测试,我们可以在控制台中看到所有输出的线程名前都是之前我们定义的线程池前缀名开始的,说明我们使用线程池来执行异步任务的试验成功了!

    2019-05-24 09:21:24.544  INFO 10756 --- [ testExecutor-2] c.a.authorization_java.util.TestMethod   : 第二个
    2019-05-24 09:21:24.543  INFO 10756 --- [ testExecutor-1] c.a.authorization_java.util.TestMethod   : 第一个
    2019-05-24 09:21:24.544  INFO 10756 --- [ testExecutor-3] c.a.authorization_java.util.TestMethod   : 第三个
    2019-05-24 09:21:26.868  INFO 10756 --- [ testExecutor-3] c.a.authorization_java.util.TestMethod   : 完成三,耗时:2324毫秒
    2019-05-24 09:21:29.774  INFO 10756 --- [ testExecutor-2] c.a.authorization_java.util.TestMethod   : 完成二,耗时:5230毫秒
    2019-05-24 09:21:31.628  INFO 10756 --- [ testExecutor-1] c.a.authorization_java.util.TestMethod   : 完成一,耗时:7084毫秒
    
  • 相关阅读:
    max-points-on-a-line
    evaluate-reverse-polish-notation
    minimum-depth-of-binary-tree
    ML&MLDS笔记:偏差 vs 方差
    机器人的运动范围
    矩阵中的路径
    滑动窗口的最大值
    数据流中的中位数
    1.微服务架构设计(英文-起源)
    5.如何复制一个文件(编程)
  • 原文地址:https://www.cnblogs.com/xzy-/p/10916189.html
Copyright © 2020-2023  润新知