Spring中提供了@Async注解用于执行异步任务,而@Schedule注解用于执行定时任务,两个都有默认的线程池配置,但是,可以通过配置文件或者自定Bean的方式来更改默认配置,今天周日,来学习一下这两个注解的自定义线程池的方法。
想要使用@Async和@Scheduled注解,需要在配置类中添加注解:@EnableScheduling和@EnableAsync注解。
在SpringBoot中,可以在配置文件中指定线程池的配置,具体配置如下:
Spring:
task:
#ThreadPoolTaskExecutor配置(@EnableAsync注解开启)TaskExecutionProperties
execution:
pool:
core-size: 8 #核心线程数量
max-size: 8 #当等待队列填满时,线程池可以扩大的数量
queue-capacity: 1000 #等待的队列长度
keep-alive: 50s #线程的最大空闲等待时长
allow-core-thread-timeout: true #是否允许核心线程超时,可以实现线程池的动态增长和萎缩
thread-name-prefix: aviator-task #自定义TaskExecutor线程名称
另外一种方式是实现AsyncConfigurer接口,在方法getAsyncExecutor中,返回自定义的线程池:
/**
* @author 熊乾坤
* @date 2020-02-21 17:06
*/
@EnableAsync
@Configuration
public class AsyncConfiguration implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncExceptionHandler();
}
@Override
public TaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.initialize();
executor.setAllowCoreThreadTimeOut(true);
executor.setCorePoolSize(8);
executor.setMaxPoolSize(8);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("aviator-task");
executor.setKeepAliveSeconds(60);
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
可以使用自定义bean的方式,来自定义Async使用的线程池,配置如下:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@EnableAsync
@Configuration
class TaskPoolConfig {
@Bean("taskExecutor")
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//此方法必须调用,否则会抛出ThreadPoolTaskExecutor未初始化异常
executor.initialize();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(20);
executor.setQueueCapacity(200);
executor.setKeepAliveSeconds(60);
executor.setThreadNamePrefix("taskExecutor-");
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
return executor;
}
}
}
上面我们通过使用ThreadPoolTaskExecutor创建了一个线程池,同时设置了以下这些参数:
CallerRunsPolicy策略,当线程池没有处理能力的时候,该策略会直接在 execute 方法的调用线程中运行被拒绝的任务;如果执行程序已关闭,则会丢弃该任务对于@Async注解的方法抛出的异常,如果需要特殊处理,则需要实现AsyncUncaughtExceptionHandler接口,在接口中对异常进行处理,代码如下:
/**
* 捕获Async注解的方法抛出的异常
*
* @author 熊乾坤
* @date 2020-04-25 12:53
*/
@Slf4j
public class MyAsyncExceptionHandler implements AsyncUncaughtExceptionHandler {
@Override
public void handleUncaughtException(Throwable ex, Method method, Object... params) {
log.error("caught async exception", ex);
}
}
然后实现AsyncConfigurer类,在类中返回该ExceptionHandler:
/**
* @author 熊乾坤
* @date 2020-02-21 17:06
*/
@EnableAsync
@Configuration
public class AsyncConfiguration implements AsyncConfigurer {
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new MyAsyncExceptionHandler();
}
}