深入理解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()会捕获指定异常,原有任务还会继续运行,直到结束。
- 在有返回值的异步调用中,异步处理抛出异常,会直接抛出异常,异步任务结束,原有处理结束执行。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作能带来一定的帮助,如果有疑问大家可以留言交流,谢谢大家对毛票票的支持。