深入理解spring boot异步调用方式@Async
本文主要给大家介绍了关于springboot异步调用方式@Async的相关内容,分享出来供大家参考学习,下面来一起看看详细的介绍:
1.使用背景
在日常开发的项目中,当访问其他人的接口较慢或者做耗时任务时,不想程序一直卡在耗时任务上,想程序能够并行执行,我们可以使用多线程来并行的处理任务,也可以使用spring提供的异步处理方式@Async。
2.异步处理方式
- 调用之后,不返回任何数据。
- 调用之后,返回数据,通过Future来获取返回数据
3.@Async不返回数据
使用@EnableAsync启用异步注解
@Configuration
@EnableAsync
@Slf4j
publicclassAsyncConfig{
}
在异步处理的方法dealNoReturnTask上添加注解@Async
@Component
@Slf4j
publicclassAsyncTask{
@Async
publicvoiddealNoReturnTask(){
log.info("Thread{}dealNoReturnTaskstart",Thread.currentThread().getName());
try{
Thread.sleep(3000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
log.info("Thread{}dealNoReturnTaskendat{}",Thread.currentThread().getName(),System.currentTimeMillis());
}
}
Test测试类:
@SpringBootTest(classes=SpringbootApplication.class)
@RunWith(SpringJUnit4ClassRunner.class)
@Slf4j
publicclassAsyncTest{
@Autowired
privateAsyncTaskasyncTask;
@Test
publicvoidtestDealNoReturnTask(){
asyncTask.dealNoReturnTask();
try{
log.info("begintodealotherTask!");
Thread.sleep(10000);
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
日志打印结果为:
begintodealotherTask! AsyncExecutorThread-1dealNoReturnTaskstart AsyncExecutorThread-1dealNoReturnTaskendat1499751227034
从日志中我们可以看出,方法dealNoReturnTask()是异步执行完成的。
dealNoReturnTask()设置sleep3s是为了模拟耗时任务
testDealNoReturnTask()设置sleep10s是为了确认异步是否执行完成
4.@Async返回数据
异步调用返回数据,Future表示在未来某个点获取执行结果,返回数据类型可以自定义
@Async publicFuturedealHaveReturnTask(){ try{ Thread.sleep(3000); }catch(InterruptedExceptione){ e.printStackTrace(); } JSONObjectjsonObject=newJSONObject(); jsonObject.put("thread",Thread.currentThread().getName()); jsonObject.put("time",System.currentTimeMillis()); returnnewAsyncResult (jsonObject.toJSONString()); }
测试类用isCancelled判断异步任务是否取消,isDone判断任务是否执行结束
@Test
publicvoidtestDealHaveReturnTask()throwsException{
Futurefuture=asyncTask.dealHaveReturnTask();
log.info("begintodealotherTask!");
while(true){
if(future.isCancelled()){
log.info("dealasynctaskisCancelled");
break;
}
if(future.isDone()){
log.info("dealasynctaskisDone");
log.info("returnresultis"+future.get());
break;
}
log.info("waitasynctasktoend...");
Thread.sleep(1000);
}
}
日志打印如下,我们可以看出任务一直在等待异步任务执行完毕,用future.get()来获取异步任务的返回结果
begintodealotherTask!
waitasynctasktoend...
waitasynctasktoend...
waitasynctasktoend...
waitasynctasktoend...
dealasynctaskisDone
returnresultis{"thread":"AsyncExecutorThread-1","time":1499752617330}
4.异常处理
我们可以实现AsyncConfigurer接口,也可以继承AsyncConfigurerSupport类来实现
在方法getAsyncExecutor()中创建线程池的时候,必须使用executor.initialize(),不然在调用时会报线程池未初始化的异常。
如果使用threadPoolTaskExecutor()来定义bean,则不需要初始化
@Configuration
@EnableAsync
@Slf4j
publicclassAsyncConfigimplementsAsyncConfigurer{
//@Bean
//publicThreadPoolTaskExecutorthreadPoolTaskExecutor(){
//ThreadPoolTaskExecutorexecutor=newThreadPoolTaskExecutor();
//executor.setCorePoolSize(10);
//executor.setMaxPoolSize(100);
//executor.setQueueCapacity(100);
//returnexecutor;
//}
@Override
publicExecutorgetAsyncExecutor(){
ThreadPoolTaskExecutorexecutor=newThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(100);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsyncExecutorThread-");
executor.initialize();//如果不初始化,导致找到不到执行器
returnexecutor;
}
@Override
publicAsyncUncaughtExceptionHandlergetAsyncUncaughtExceptionHandler(){
returnnewAsyncExceptionHandler();
}
}
异步异常处理类:
@Slf4j
publicclassAsyncExceptionHandlerimplementsAsyncUncaughtExceptionHandler{
@Override
publicvoidhandleUncaughtException(Throwableex,Methodmethod,Object...params){
log.info("Asyncmethod:{}hasuncaughtexception,params:{}",method.getName(),JSON.toJSONString(params));
if(exinstanceofAsyncException){
AsyncExceptionasyncException=(AsyncException)ex;
log.info("asyncException:{}",asyncException.getErrorMessage());
}
log.info("Exception:");
ex.printStackTrace();
}
}
异步处理异常类:
@Data
@AllArgsConstructor
publicclassAsyncExceptionextendsException{
privateintcode;
privateStringerrorMessage;
}
- 在无返回值的异步调用中,异步处理抛出异常,AsyncExceptionHandler的handleUncaughtException()会捕获指定异常,原有任务还会继续运行,直到结束。
- 在有返回值的异步调用中,异步处理抛出异常,会直接抛出异常,异步任务结束,原有处理结束执行。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。