1、本文内容
详解 @EnableAsync & @Async,主要分下面几个点进行介绍。
作用
用法
获取异步执行结果
自定义异步执行的线程池
自定义异常处理
线程隔离
源码 & 原理
2、作用
spring容器中实现bean方法的异步调用。
比如有个logService的bean,logservice中有个log方法用来记录日志,当调用logService.log(msg)的时候,希望异步执行,那么可以通过@EnableAsync & @Async来实现。
3、用法
2步
需要异步执行的方法上面使用@Async注解标注,若bean中所有的方法都需要异步执行,可以直接将@Async加载类上。
将@EnableAsync添加在spring配置类上,此时@Async注解才会起效。
常见2种用法
无返回值的
可以获取返回值的
4、无返回值的
用法
方法返回值不是Future类型的,被执行时,会立即返回,并且无法获取方法返回值,如:
@Async
public void log(String msg) throws InterruptedException {
System.out.println(“开始记录日志,” + System.currentTimeMillis());
//模拟耗时2秒
TimeUnit.SECONDS.sleep(2);
System.out.println(“日志记录完毕,” + System.currentTimeMillis());
}
5、获取异步返回值
用法
若需取异步执行结果,方法返回值必须为Future类型,使用spring提供的静态方法org.springframework.scheduling.annotation.AsyncResult#forValue创建返回值,如:
public Future getGoodsInfo(long goodsId) throws InterruptedException {
return AsyncResult.forValue(String.format(“商品%s基本信息!”, goodsId));
}
6、自定义异步执行的线程池
默认情况下,@EnableAsync使用内置的线程池来异步调用方法,不过我们也可以自定义异步执行任务的线程池。
有2种方式来自定义异步处理的线程池
方式1
在spring容器中定义一个线程池类型的bean,bean名称必须是taskExecutor
@Bean
public Executor taskExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(100);
executor.setThreadNamePrefix("my-thread-");
return executor;
}
方式2
定义一个bean,实现AsyncConfigurer接口中的getAsyncExecutor方法,这个方法需要返回自定义的线程池,案例代码:
import com.javacode.async.demo1.LogService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import java.util.concurrent.Executor;
@EnableAsync
public class MainConfig3 {
@Bean
public LogService logService() {
return new LogService();
}
/**
* 定义一个AsyncConfigurer类型的bean,实现getAsyncExecutor方法,返回自定义的线程池
*
* @param executor
* @return
*/
@Bean
public AsyncConfigurer asyncConfigurer(@Qualifier("logExecutors") Executor executor) {
return new AsyncConfigurer