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

我们常用ThreadPoolExecutor提供的线程池服务,springboot框架提供了@Async注解,帮助我们更方便的将业务逻辑提交到线程池中异步执行,今天我们就来实战体验这个线程池服务;

1 进行线程池配置

@EnableAsync
@Configuration
public class TaskPoolConfig {
    @Bean("taskExecutor")
    public Executor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
         //核心线程池大小
        executor.setCorePoolSize(10);
        //最大线程数
        executor.setMaxPoolSize(20);
        //队列容量
        executor.setQueueCapacity(200);
        //活跃时间
        executor.setKeepAliveSeconds(60);
        //线程名字前缀
        executor.setThreadNamePrefix("taskExecutor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }
}

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

2使用线程池

在方法名上用@Async注解中指定线程池名即可,TaskPoolConfig.java中@Bean的value值

@Async("taskExecutor")
public void doTaskOne() throws Exception {
    log.info("开始做任务一");
    long start = System.currentTimeMillis();
    Thread.sleep(random.nextInt(10000));
    long end = System.currentTimeMillis();
    log.info("完成任务一,耗时:" + (end - start) + "毫秒");
}

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

3 单元测试

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class ThreadTaskTest {
    @Autowired
    private ThreadTask task;

    @Test
    public void test() throws Exception {
        task.doTaskOne();
        task.doTaskTwo();

        Thread.currentThread().join();
    }
}

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

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