【注解说明】
@Async是Spring框架中用于支持异步方法执行。使用时需要在配置类上添加@EnableAsync注解开启异步。
配置类建议单独创建 如创建 AsyncConfig类 添加 @Configuration @EnableAsync, 该配置类下建议放置线程池相应配置。
【使用前提】
- @Async添加的方法需要修饰为public 且无特殊配置不能出现本类方法调用Async方法,此时异步不生效
- @Async需要指定线程池,不同业务建议使用不同线程池
- @Async不要同@Transactional等类似注解一起使用,可能导致失效
- @EnableAsync注解上的proxyTargetClass建议设置为true
【线程池示例】
/**
* 异步线程配置
*/
@EnableAsync(proxyTargetClass = true)
@Configuration
public class AsyncConfig {
@Bean("testExecutor")
public TaskExecutor apiLogExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 设置核心线程数
executor.setCorePoolSize(5);
// 设置最大线程数
executor.setMaxPoolSize(20);
// 设置队列容量
executor.setQueueCapacity(200);
// 设置线程活跃时间(秒)
executor.setKeepAliveSeconds(30);
// 设置默认线程名称
executor.setThreadNamePrefix("test-");
// 设置拒绝策略
executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
// 等待所有任务结束后再关闭线程池
executor.setWaitForTasksToCompleteOnShutdown(true);
return executor;
}
}
【使用场景①】主线程不关心异步处理结果,不进行等待,大部分业务如此使用
@Service
public class MyAService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyAService.class);
@Async("testExecutor")
public void doA(int param) {
LOGGER.info("开始异步执行A事件,入参:{}", param);
// do A things
LOGGER.info("结束异步执行A事件");
}
}
@Service
public class Test {
@Resource
private MyAService aService;
public void testA(int a) {
int i = 111 * 77 * a;
//do somethings
//async to do a
aService.doA(i);
}
}
【使用场景②】主线程需要等待异步结果执行完成后再继续,可以设置成功或失败的回调
PS: 注意此时返回值要为Future<XXX>, 不能设置为AsyncResult,不然会报类型转换错误。
Spring框架使用时实际返回实现类为 ListenableFutureTask,用AsyncResult同为Future父类不能互相转换
@Service
public class MyBService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyBService.class);
@Async("testExecutor")
public Future<String> doB(int param) {
LOGGER.info("开始异步执行B事件,入参:{}", param);
// do B things
LOGGER.info("结束异步执行B事件");
//返回异步执行结果
return new AsyncResult<>("success");
}
}
@Service
public class TestB {
@Resource
private MyBService bService;
public void testB(int b) {
int i = 111 * 77 * b;
//do somethings
//async to do B
Future<String> future = bService.doB(i);
//若要一直等待异步执行 使用get
try {
String result = future.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
public void testB2(int b) {
int i = 111 * 77 * b;
//do somethings
//async to do B
Future<String> future = bService.doB(i);
//若等待XX时间内没返回结果就置为超时,
try {
String timeOutResult = future.get(3L, TimeUnit.SECONDS);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
}
}