1.介绍
工作中经常涉及异步任务,通常是使用多线程技术,比如线程池ThreadPoolExecutor,但使用Executors容易产生OOM,需要手动使用ThreadPoolExecutor创建线程池;在springboot使用 @async 可以实现异步调用,配置线程池参数,可以简单的实现多线程的线程池效果,从而简化开发,避免OOM;
2.异步调用,无返回结果
首先在启动类上加上@EnableAsync 注解
@SpringBootApplication
@EnableAsync
public class AsyncApplication {
public static void main(String[] args) {
SpringApplication.run(AsyncApplication.class,args);
}
}
在函数上标上@sync注解,表示异步调用
@Async
public void exec2(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("exec2 执行完毕");
}
@GetMapping("exec2")
public String exec2(){
mainService.exec2();
return "exec2";
}
测试:浏览器立即返回结果,3秒之后后台才打印输出日志
2.异步调用,有返回值
@Async
public Future<String> exec3_1(){
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("exec3_1 执行完毕");
return new AsyncResult<>("exec3_1");
}
@Async
public Future<String> exec3_2(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
log.info("exec3_2 执行完毕");
return new AsyncResult<>("exec3_2");
}
@GetMapping("exec3")
public String exec3() throws ExecutionException, InterruptedException {
Future<String> exec3_1 = mainService.exec3_1();
Future<String> exec3_2 = mainService.exec3_2();
String result="";
while (true){
if(exec3_1.isDone() && exec3_2.isDone()){
result=exec3_1.get()+"--"+exec3_2.get();
break;
}
}
return result;
}
测试:3秒后浏览器返回结果
4.线程池
在异步掉用中使用的@Async 注解,默认的线程池大小如下
# 核心线程数
spring.task.execution.pool.core-size=8
# 最大线程数
spring.task.execution.pool.max-size=16
# 空闲线程存活时间
spring.task.execution.pool.keep-alive=60s
# 是否允许核心线程超时
spring.task.execution.pool.allow-core-thread-timeout=true
# 线程队列数量
spring.task.execution.pool.queue-capacity=100
# 线程关闭等待
spring.task.execution.shutdown.await-termination=false
spring.task.execution.shutdown.await-termination-period=
# 线程名称前缀
spring.task.execution.thread-name-prefix=task-
一般情况下,我们都需要手动创建线程池,使用 ThreadPoolTaskExecutor 类进行配置
@Configuration
public class PoolConfig {
@Bean
public TaskExecutor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(10);
// 设置最大线程数
executor.setMaxPoolSize(15);
// 设置队列容量
executor.setQueueCapacity(20);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(60);
// 设置默认线程名称
executor.setThreadNamePrefix("zszxz-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}