合理使用异步方法可以提高接口性能。异步方法适用于逻辑与逻辑之间可以相互分割互不影响的业务中。
SpringBoot 支持异步方法调用。具体用法:
- 在启动类添加@EnableAsync注解,声明开启异步方法
- 在异步方法添加@Async注解,被@Async注解修改的方法由SpringBoot默认线程池(SimpleAsyncTaskExecutor)执行。
注意:
-
异步方法可以不使用默认线程池 SimpleAsyncTaskExecutor,可以自定义线程池执行。
-
如果直接将需要异步操作的方法写到业务类中,业务类直接调用,异步方法会失效。因为@Async的调用涉及到动态代理,业务类直接调用的话,则执行逻辑不会走到代理类。因此需要将 @Async 注解的方法单独拿出来封装到一个类中,再将这个类注入到业务类中,业务类通过这个类来调用异步方法
-
如果要获取异步方法的返回值,需要使用Future类及其子类来接收异步方法返回值,推荐使用
CompletableFuture
。
自定义线程池执行异步方法
1.新增线程池配置类
package com.study.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
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
public class TaskThreadPoolConfig {
private static final Logger logger = LoggerFactory.getLogger(TaskThreadPoolConfig.class);
@Value("${task.execution.pool.core-size}")
private int corePoolSize;
@Value("${task.execution.pool.max-size}")
private int maxPoolSize;
@Value("${task.execution.pool.queue-capacity}")
private int queueCapacity;
@Value("${task.execution.pool.keep-alive}")
private int keepAliveSeconds;
@Value("${task.execution.pool.name-prefix}")
private String namePrefix;
@Bean("executeService")
public Executor asyncServiceExecutor() {
logger.info("start asyncServiceExecutor");
//ThreadPoolTaskExecutor是Spring提供的线程池,底层也是使用JDK的ThreadPoolExecutor实现的。
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
//配置核心线程数
threadPoolTaskExecutor.setCorePoolSize(corePoolSize);
//配置最大线程数
threadPoolTaskExecutor.setMaxPoolSize(maxPoolSize);
//配置队列大小
threadPoolTaskExecutor.setQueueCapacity(queueCapacity);
//当线程数大于核心线程数,终止多余线程等待新任务的最长时间
threadPoolTaskExecutor.setKeepAliveSeconds(keepAliveSeconds);
//配置线程池中的线程的名称前缀
threadPoolTaskExecutor.setThreadNamePrefix(namePrefix);
//配置线程的饱和策略。CALLER_RUNS:不在新线程中执行任务,而是有调用者所在的线程来执行
threadPoolTaskExecutor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
//执行初始化
threadPoolTaskExecutor.initialize();
return threadPoolTaskExecutor;
}
}
2.在Async注解指定使用的线程池
@Async("executeService")
使用CompletableFuture获取异步方法返回值
比如:在业务类要异步(method1和method2)获取信息组合到infoMap集合并返回数据。
// 数据1
CompletableFuture<String> data1 = this.testService.method1();
// 数据2
CompletableFuture<String> data2 = this.testService.method2();
//allOf() 方法会等到所有的 CompletableFuture 都运行完成之后再返回.调用 join() 可以让程序等所有CompletableFuture都运行完了之后再继续执行。
CompletableFuture.allOf(data1, data2).join();
infoMap.put("data1", data1.get());
infoMap.put("data2", data2.get());