一.作用
总结,被Async注解的方法会开启一个新的线程来异步处理代码逻辑,如果放在类上,那么类里面的所有方法被调用时候,都会异步调用。
举例解释:如果一个接口,接口中需要调用A远程方法(返回数字),然后调用B远程方法(返回数字),然后将两个数据结果做加法作为最终的接口返回,A调用需要3秒,B需要2秒,那么如果按顺序执行,则调用需要5秒时间才可以获取到数据,如果使用异步,那么A和B同时执行,则只需要3秒即可返回数据。
二.配置
1.在Springboot启动类上加上@EnableAsync注解,开启异步处理。
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
2.线程池配置(非必须,如果不配置将使用springboot默认配置)。
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
import java.util.concurrent.ThreadPoolExecutor;
@Configuration
@Slf4j
public class AsyncConfig {
// 配置核心线程数
private int corePoolSize = 5;
// 配置最大线程数
private int maxPoolSize = 20;
// 配置任务队列的长度
private int queueCapacity = 500;
// 配置任务的空闲时间
private int aliveSeconds = 600;
// 配置线程前缀
private String namePrefix = "localThreadPool";
// 自定义线程池
@Bean(name = "localAsyncExecutor")
public Executor asyncServiceExecutor() {
log.info("初始化 springboot 线程池");
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
//配置核心线程数
executor.setCorePoolSize(corePoolSize);
//配置最大线程数
executor.setMaxPoolSize(maxPoolSize);
//配置队列大小
executor.setQueueCapacity(queueCapacity);
//配置线程池中的线程的名称前缀
executor.setThreadNamePrefix(namePrefix);
//配置线程的空闲时间
executor.setKeepAliveSeconds(aliveSeconds);
// RejectedExecutionHandler:当pool已经达到max size的时候,如何处理新任务
// CallerRunsPolicy:不在新线程中执行任务,而是有调用者所在的线程来执行
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
executor.initialize();
log.info("springboot 线程池初始化完毕");
return executor;
}
}
3.新建一个统一管理异步处理的类(不能用业务service里面添加异步的方法,需要新建)
其中Future<Integer>中的Integer表示异步返回的数据类型,@Async注解的方法只能返回Future<T>或者void类型。
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;
import java.util.concurrent.Future;
@Component
@Slf4j
//注解在类上,表示此类中的所有方法都是异步的方法,里面的参数表示
//从哪个线程池里面创建线程,需要和创建线程的线程池Bean的name配置保持一致
@Async("localAsyncExecutor")
public class AsyncManager {
public Future<Integer> task1() {
log.info("任务1执行");
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AsyncResult(1);
}
public Future<Integer> task2() {
log.info("任务2执行");
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AsyncResult(2);
}
public Future<Integer> task3() {
log.info("任务3执行");
try {
Thread.currentThread().sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AsyncResult(3);
}
}
4.在方法中调用异步处理
@Autowired
private AsyncManager asyncManager;
@GetMapping("async")
public int sum() throws ExecutionException, InterruptedException {
long start = System.nanoTime();
Future<Integer> future1 = asyncManager.task1();
Future<Integer> future2 = asyncManager.task2();
Future<Integer> future3 = asyncManager.task3();
int result= future1.get()+future2.get()+future3.get();
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
long use = System.nanoTime() - start;
long convert = TimeUnit.SECONDS.convert(use, TimeUnit.NANOSECONDS);
log.info("耗时:"+convert);
return result;
}