详解SpringBoot中的异步调用@Async

2025-05-27 0 40

详解SpringBoot中的异步调用@Async

如何开启异步调用

SpringBoot中,只需要给方法加上@Async注解,就能将同步方法变为异步调用

首先在启动类上添加@EnableAsync,即开启异步调用

  1. /**
  2. *@authorqcy
  3. */
  4. @SpringBootApplication
  5. @EnableAsync
  6. publicclassAsyncApplication{
  7. publicstaticvoidmain(String[]args){
  8. SpringApplication.run(AsyncApplication.class,args);
  9. }
  10. }

在需要异步调用的方法上加上@Async注解

  1. packagecom.yang.async;
  2. importlombok.extern.slf4j.Slf4j;
  3. importorg.springframework.scheduling.annotation.Async;
  4. importorg.springframework.scheduling.annotation.AsyncResult;
  5. importorg.springframework.stereotype.Component;
  6. importjava.util.concurrent.Future;
  7. importjava.util.concurrent.FutureTask;
  8. /**
  9. *@authorqcy
  10. *@create2020/09/0914:01:35
  11. */
  12. @Slf4j
  13. @Component
  14. publicclassTask{
  15. @Async
  16. publicvoidmethod1(){
  17. log.info("method1开始,执行线程为"+Thread.currentThread().getName());
  18. try{
  19. Thread.sleep(2000);
  20. }catch(InterruptedExceptione){
  21. e.printStackTrace();
  22. }
  23. log.info("method1结束");
  24. }
  25. @Async
  26. publicvoidmethod2(){
  27. log.info("method2开始,执行线程为"+Thread.currentThread().getName());
  28. try{
  29. Thread.sleep(3000);
  30. }catch(InterruptedExceptione){
  31. e.printStackTrace();
  32. }
  33. log.info("method2结束");
  34. }
  35. }

测试一下:

  1. @SpringBootTest
  2. @Slf4j
  3. publicclassAsyncApplicationTests{
  4. @Autowired
  5. Tasktask;
  6. @Test
  7. publicvoidtestAsyncWithVoidReturn()throwsInterruptedException{
  8. log.info("main线程开始");
  9. task.method1();
  10. task.method2();
  11. //确保两个异步调用执行完成
  12. Thread.sleep(6000);
  13. log.info("main线程结束");
  14. }
  15. }

输出如下:

详解SpringBoot中的异步调用@Async

可以看得出,SpringBoot创建了一个名为applicationTaskExecutor的线程池,使用这里面的线程来执行异步调用

这里值得注意的是,不要在一个类中调用@Async标注的方法,否则不会起到异步调用的作用,至于为什么会产生这样的问题,需要深入到源码中一探究竟,会另开篇幅。

既然默认使用的是SpringBoot自己创建的applicationTaskExecutor,那如何自己去定义一个线程池呢?

自定义线程池

我们需要手动创建一个名为asynTaskExecutord的Bean

  1. packagecom.yang.async;
  2. importlombok.extern.slf4j.Slf4j;
  3. importorg.springframework.context.annotation.Bean;
  4. importorg.springframework.context.annotation.Configuration;
  5. importorg.springframework.core.task.AsyncTaskExecutor;
  6. importorg.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
  7. importjava.util.concurrent.ThreadPoolExecutor;
  8. /**
  9. *@authorqcy
  10. *@create2020/09/0915:31:07
  11. */
  12. @Slf4j
  13. @Configuration
  14. publicclassAsyncConfig{
  15. @Bean
  16. publicAsyncTaskExecutorasyncTaskExecutor(){
  17. ThreadPoolTaskExecutorexecutor=newThreadPoolTaskExecutor();
  18. executor.setCorePoolSize(8);
  19. executor.setMaxPoolSize(16);
  20. executor.setQueueCapacity(50);
  21. executor.setAllowCoreThreadTimeOut(true);
  22. executor.setKeepAliveSeconds(10);
  23. executor.setRejectedExecutionHandler(newThreadPoolExecutor.CallerRunsPolicy());
  24. executor.setThreadNamePrefix("async-thread-pool-thread");
  25. returnexecutor;
  26. }
  27. }

对以上参数不了解的同学,可以参考我的这篇文章说说线程池

其他类不需要变动,直接运行刚才的testAsyncWithVoidReturn()方法,输出:

详解SpringBoot中的异步调用@Async

看得出来,现在是我们自定义的线程池

如果关心异步调用的返回值,又怎么处理?

获取异步调用的返回结果

获取异步调用的结果,需要利用Future机制,可以参考我的另外一篇文章谈谈Runnable、Future、Callable、FutureTask之间的关系

为Task类增加以下两个方法:

  1. @Async
  2. publicFuture<String>method3(){
  3. log.info("method3开始,执行线程为"+Thread.currentThread().getName());
  4. try{
  5. Thread.sleep(1000);
  6. }catch(InterruptedExceptione){
  7. e.printStackTrace();
  8. }
  9. log.info("method3结束");
  10. returnnewAsyncResult<>("method3");
  11. }
  12. @Async
  13. publicFuture<String>method4(){
  14. log.info("method4开始,执行线程为"+Thread.currentThread().getName());
  15. try{
  16. Thread.sleep(3000);
  17. }catch(InterruptedExceptione){
  18. e.printStackTrace();
  19. }
  20. log.info("method4结束");
  21. returnnewAsyncResult<>("method4");
  22. }

测试类:

  1. @Test
  2. publicvoidtestAsyncWithStringReturn()throwsInterruptedException,ExecutionException{
  3. log.info("main线程开始");
  4. Future<String>method3Result=task.method3();
  5. Future<String>method4Result=task.method4();
  6. //get方法为阻塞获取
  7. log.info("method3执行的返回结果:{}",method3Result.get());
  8. log.info("method4执行的返回结果:{}",method4Result.get());
  9. log.info("main线程结束");
  10. }

输出:

详解SpringBoot中的异步调用@Async

如图,在主线程结束前,获取到了异步调用的结果。且在两个异步调用都结束的情况下,继续执行主线程。

原文地址:https://www.toutiao.com/i6944877804123079207/

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 详解SpringBoot中的异步调用@Async https://www.kuaiidc.com/76177.html

相关文章

发表评论
暂无评论