转自:
1、启动类添加注解,开启异步支持
@EnableAsync//开启异步处理支持,开启springboot线程池
2、配置线程池
2.1、给springboot提供默认的线程池
@PropertySource(value="classpath:config.properties")是用来读取自定义配置文件的,如果配置信息放在了application.properties中无需使用。
@Slf4j
@Configuration
@PropertySource(value="classpath:config.properties")
public class AsyncExecuteThreadPool implements AsyncConfigurer {
@Value("${async.pool.corePoolSize}")
private int corePoolSize;//核心线程池大小
@Value("${async.pool.maxPoolSize}")
private int maxPoolSize;//最大线程数
@Value("${async.pool.keepAliveSeconds}")
private int keepAliveSeconds;//活跃时间
@Value("${async.pool.queueCapacity}")
private int queueCapacity;//队列容量
@Override
public Executor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//核心线程池大小
executor.setCorePoolSize(corePoolSize);
//最大线程数
executor.setMaxPoolSize(maxPoolSize);
//队列容量
executor.setQueueCapacity(queueCapacity);
//活跃时间
executor.setKeepAliveSeconds(keepAliveSeconds);
//线程名字前缀
executor.setThreadNamePrefix("CP Thread-");
// setRejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是由调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
executor.initialize();
return executor;
}
/**
* 异步任务中异常处理
* @return
*/
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new AsyncUncaughtExceptionHandler() {
@Override
public void handleUncaughtException(Throwable arg0, Method arg1, Object... arg2) {
log.error("=========================="+arg0.getMessage()+"=======================", arg0);
log.error("exception method:"+arg1.getName());
}
};
}
}
2.2 配置多个线程池,指定需要使用的
@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());
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
return executor;
}
}
上面我们通过ThreadPoolTaskExecutor
创建了一个线程池,同时设置了如下参数:
- 核心线程数10:线程池创建时初始化的线程数
- 最大线程数20:线程池最大的线程数,只有在缓冲队列满了之后才会申请超过核心线程数的线程
- 缓冲队列200:用来缓冲执行任务的队列
- 允许线程的空闲时间60秒:超过了核心线程数之外的线程,在空闲时间到达之后会被销毁
- 线程池名的前缀:设置好了之后可以方便我们定位处理任务所在的线程池
- 线程池对拒绝任务的处理策略:此处采用了
CallerRunsPolicy
策略,当线程池没有处理能力的时候,该策略会直接在execute
方法的调用线程中运行被拒绝的任务;如果执行程序已被关闭,则会丢弃该任务 - 设置线程池关闭的时候等待所有任务都完成再继续销毁其他的Bean
- 设置线程池中任务的等待时间,如果超过这个时候还没有销毁就强制销毁,以确保应用最后能够被关闭,而不是阻塞住。
使用线程池
- 只需要在
@Async
注解中指定线程池名即可
@Slf4j
@Component
public class Task {
public static Random random = new Random();
@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) + "毫秒");
}
@Async("taskExecutor")
public void doTaskTwo() throws Exception {
log.info("开始做任务二");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("完成任务二,耗时:" + (end - start) + "毫秒");
}
}