• Spring Boot使用@Async实现异步调用


    原文:http://blog.csdn.net/a286352250/article/details/53157822

    项目GitHub地址 :

    https://github.com/FrameReserve/TrainingBoot

    Spring Boot(十)使用@Async实现异步调用 ,标记地址:

    https://github.com/FrameReserve/TrainingBoot/releases/tag/0.0.10

    Spring Boot启动类,增加@EnableAsync注解配置:

    src/main/java/com/training/SpringBootServlet.java

    [java] view plain copy
     
    1. package com.training;  
    2.   
    3. import org.springframework.boot.SpringApplication;  
    4. import org.springframework.boot.autoconfigure.SpringBootApplication;  
    5. import org.springframework.boot.builder.SpringApplicationBuilder;  
    6. import org.springframework.boot.web.support.SpringBootServletInitializer;  
    7. import org.springframework.scheduling.annotation.EnableAsync;  
    8.   
    9. @SpringBootApplication  
    10. @EnableAsync  
    11. public class SpringBootServlet extends SpringBootServletInitializer {  
    12.   
    13.     // jar启动  
    14.     public static void main(String[] args) {  
    15.         SpringApplication.run(SpringBootServlet.class, args);  
    16.     }  
    17.   
    18.     // tomcat war启动  
    19.     @Override  
    20.     protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {  
    21.         return application.sources(SpringBootServlet.class);  
    22.     }  
    23.   
    24. }  

    测试:

    增加异步方法Service,线程休眠:

    [java] view plain copy
     
    1. package com.training.async.service.impl;  
    2.   
    3. import java.util.Random;  
    4. import java.util.concurrent.Future;  
    5.   
    6. import org.springframework.scheduling.annotation.Async;  
    7. import org.springframework.scheduling.annotation.AsyncResult;  
    8. import org.springframework.stereotype.Service;  
    9.   
    10. import com.training.async.service.DemoAsyncService;  
    11.   
    12. @Service  
    13. public class DemoAsyncServiceImpl implements DemoAsyncService {  
    14.   
    15.     public static Random random =new Random();  
    16.   
    17.     @Async  
    18.     public Future<String> doTaskOne() throws Exception {  
    19.         System.out.println("开始做任务一");  
    20.         long start = System.currentTimeMillis();  
    21.         Thread.sleep(random.nextInt(10000));  
    22.         long end = System.currentTimeMillis();  
    23.         System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");  
    24.         return new AsyncResult<>("任务一完成");  
    25.     }  
    26.   
    27.     @Async  
    28.     public Future<String> doTaskTwo() throws Exception {  
    29.         System.out.println("开始做任务二");  
    30.         long start = System.currentTimeMillis();  
    31.         Thread.sleep(random.nextInt(10000));  
    32.         long end = System.currentTimeMillis();  
    33.         System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");  
    34.         return new AsyncResult<>("任务二完成");  
    35.     }  
    36.   
    37.     @Async  
    38.     public Future<String> doTaskThree() throws Exception {  
    39.         System.out.println("开始做任务三");  
    40.         long start = System.currentTimeMillis();  
    41.         Thread.sleep(random.nextInt(10000));  
    42.         long end = System.currentTimeMillis();  
    43.         System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");  
    44.         return new AsyncResult<>("任务三完成");  
    45.     }  
    46.       
    47. }  

    调用异步测试测试,查看控制台输出执行顺序:

    [java] view plain copy
     
    1. package com.training.async.controller;  
    2.   
    3. import io.swagger.annotations.ApiOperation;  
    4.   
    5. import java.util.concurrent.Future;  
    6.   
    7. import javax.annotation.Resource;  
    8.   
    9. import org.springframework.web.bind.annotation.RequestMapping;  
    10. import org.springframework.web.bind.annotation.RequestMethod;  
    11. import org.springframework.web.bind.annotation.ResponseBody;  
    12. import org.springframework.web.bind.annotation.RestController;  
    13.   
    14. import com.training.async.service.DemoAsyncService;  
    15. import com.training.core.dto.ResultDataDto;  
    16.   
    17. @RestController  
    18. @RequestMapping(value="/async")   
    19. public class DemoAsyncController {  
    20.   
    21.     @Resource  
    22.     private DemoAsyncService demoAsyncService;  
    23.   
    24.     /** 
    25.      * 测试异步方法调用顺序 
    26.      */  
    27.     @ApiOperation(value="测试异步方法调用顺序", notes="getEntityById")  
    28.     @RequestMapping(value = "/getTestDemoAsync", method = RequestMethod.GET)  
    29.     public @ResponseBody ResultDataDto getEntityById() throws Exception {  
    30.           
    31.         long start = System.currentTimeMillis();  
    32.   
    33.         Future<String> task1 = demoAsyncService.doTaskOne();  
    34.         Future<String> task2 = demoAsyncService.doTaskTwo();  
    35.         Future<String> task3 = demoAsyncService.doTaskThree();  
    36.   
    37.         while(true) {  
    38.             if(task1.isDone() && task2.isDone() && task3.isDone()) {  
    39.                 // 三个任务都调用完成,退出循环等待  
    40.                 break;  
    41.             }  
    42.             Thread.sleep(1000);  
    43.         }  
    44.   
    45.         long end = System.currentTimeMillis();  
    46.   
    47.         System.out.println("任务全部完成,总耗时:" + (end - start) + "毫秒");  
    48.         return ResultDataDto.addSuccess();  
    49.     }  
    50. }  

    原文:http://blog.csdn.net/v2sking/article/details/72795742

    什么是异步调用?

    异步调用是相对于同步调用而言的,同步调用是指程序按预定顺序一步步执行,每一步必须等到上一步执行完后才能执行,异步调用则无需等待上一步程序执行完即可执行。

    如何实现异步调用?

    多线程,这是很多人第一眼想到的关键词,没错,多线程就是一种实现异步调用的方式。

    在非spring目项目中我们要实现异步调用的就是使用多线程方式,可以自己实现Runable接口或者集成Thread类,或者使用jdk1.5以上提供了的Executors线程池。

    StrngBoot中则提供了很方便的方式执行异步调用。

    按照官方示例开撸

    代码入下

    maven依赖:

    [java] view plain copy
     
    1. <parent>  
    2.     <groupId>org.springframework.boot</groupId>  
    3.     <artifactId>spring-boot-starter-parent</artifactId>  
    4.     <version>1.5.3.RELEASE</version>  
    5. </parent>  
    6. <dependencies>  
    7.     <dependency>  
    8.         <groupId>org.springframework.boot</groupId>  
    9.         <artifactId>spring-boot-starter-web</artifactId>  
    10.     </dependency>  
    11. </dependencies>  

    启动类:添加@EnableAsync注解

    [java] view plain copy
     
    1. @SpringBootApplication  
    2. @EnableAsync  
    3. public class Application{  
    4.   
    5.     public static void main(String[] args) {  
    6.         SpringApplication.run(Application.class, args);  
    7.     }  
    8. }  



    Controller 

    只需在需要异步执行方法上添加@Async注解

    [java] view plain copy
     
    1. @RestController  
    2. @RequestMapping("")  
    3. public class AsyncTaskController {  
    4.       
    5.     @RequestMapping("")  
    6.     public String doTask() throws InterruptedException{  
    7.         long currentTimeMillis = System.currentTimeMillis();  
    8.         this.task1();  
    9.         this.task2();  
    10.         this.task3();  
    11.         long currentTimeMillis1 = System.currentTimeMillis();  
    12.         return "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";  
    13.     }  
    14.       
    15.     @Async  
    16.     public void task1() throws InterruptedException{  
    17.         long currentTimeMillis = System.currentTimeMillis();  
    18.         Thread.sleep(1000);  
    19.         long currentTimeMillis1 = System.currentTimeMillis();  
    20.         System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    21.     }  
    22.       
    23.     @Async  
    24.     public void task2() throws InterruptedException{  
    25.         long currentTimeMillis = System.currentTimeMillis();  
    26.         Thread.sleep(2000);  
    27.         long currentTimeMillis1 = System.currentTimeMillis();  
    28.         System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    29.     }  
    30.     @Async  
    31.     public void task3() throws InterruptedException{  
    32.         long currentTimeMillis = System.currentTimeMillis();  
    33.         Thread.sleep(3000);  
    34.         long currentTimeMillis1 = System.currentTimeMillis();  
    35.         System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    36.     }  
    37. }  

    main函数运行spirngboot项目,启动完成后浏览器访问:

    http://localhost:8080/

    控制台:

    [html] view plain copy
     
    1. task1任务耗时:1012ms  
    2. task2任务耗时:2009ms  
    3. task3任务耗时:3004ms  
     

    等了一段浏览器时候输出入下:

    [html] view plain copy
     
    1. task任务总耗时:6002ms   



    异步并没有执行!

    难道是代码写错了?反复检查了好几遍,并没有发现什么明显错误,想起spring对@Transactional注解时也有类似问题,spring扫描时具有@Transactional注解方法的类时,是生成一个代理类,由代理类去开启关闭事务,而在同一个类中,方法调用是在类体内执行的,spring无法截获这个方法调用。

    豁然开朗,将异步任务单独放到一个类中,调整代码入下:

    Controller

    [java] view plain copy
     
    1. @RequestMapping("")  
    2. @RestController  
    3. public class AsyncTaskController {  
    4.       
    5.     @Autowired  
    6.     private AsyncTask asyncTask;  
    7.       
    8.     @RequestMapping("")  
    9.     public String doTask() throws InterruptedException{  
    10.         long currentTimeMillis = System.currentTimeMillis();  
    11.         asyncTask.task1();  
    12.         asyncTask.task2();  
    13.         asyncTask.task3();  
    14.         long currentTimeMillis1 = System.currentTimeMillis();  
    15.         return "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";  
    16.           
    17.     }  
    18. }  

    异步任务类

    [java] view plain copy
     
    1. @Component  
    2. public class AsyncTask {  
    3.       
    4.     @Async  
    5.     public void task1() throws InterruptedException{  
    6.         long currentTimeMillis = System.currentTimeMillis();  
    7.         Thread.sleep(1000);  
    8.         long currentTimeMillis1 = System.currentTimeMillis();  
    9.         System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    10.     }  
    11.       
    12.     @Async  
    13.     public void task2() throws InterruptedException{  
    14.         long currentTimeMillis = System.currentTimeMillis();  
    15.         Thread.sleep(2000);  
    16.         long currentTimeMillis1 = System.currentTimeMillis();  
    17.         System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    18.     }  
    19.     @Async  
    20.     public void task3() throws InterruptedException{  
    21.         long currentTimeMillis = System.currentTimeMillis();  
    22.         Thread.sleep(3000);  
    23.         long currentTimeMillis1 = System.currentTimeMillis();  
    24.         System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    25.     }  
    26. }  

    控制台:

    [html] view plain copy
     
    1. task1任务耗时:1012ms  
    2. task2任务耗时:2009ms  
    3. task3任务耗时:3004ms  


    访问浏览器结果入下:

    [html] view plain copy
     
    1. task任务总耗时:19ms  
     

    异步调用成功!

    如何知道三个异步任务什么时候执行完,执行的结果怎样呢?可以采用添加Fature回调方式判断

    代码入下:

    异步任务类

    [java] view plain copy
     
    1. @Component  
    2. public class AsyncTask {  
    3.       
    4.     @Async  
    5.     public Future<String> task1() throws InterruptedException{  
    6.         long currentTimeMillis = System.currentTimeMillis();  
    7.         Thread.sleep(1000);  
    8.         long currentTimeMillis1 = System.currentTimeMillis();  
    9.         System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    10.         return new AsyncResult<String>("task1执行完毕");  
    11.     }  
    12.       
    13.     @Async  
    14.     public Future<String> task2() throws InterruptedException{  
    15.         long currentTimeMillis = System.currentTimeMillis();  
    16.         Thread.sleep(2000);  
    17.         long currentTimeMillis1 = System.currentTimeMillis();  
    18.         System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    19.         return new AsyncResult<String>("task2执行完毕");  
    20.     }  
    21.     @Async  
    22.     public Future<String> task3() throws InterruptedException{  
    23.         long currentTimeMillis = System.currentTimeMillis();  
    24.         Thread.sleep(3000);  
    25.         long currentTimeMillis1 = System.currentTimeMillis();  
    26.         System.out.println("task3任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");  
    27.         return new AsyncResult<String>("task3执行完毕");  
    28.     }  
    29. }  


    Controller

    [java] view plain copy
     
    1. @RequestMapping("")  
    2. @RestController  
    3. public class AsyncTaskController {  
    4.       
    5.     @Autowired  
    6.     private AsyncTask asyncTask;  
    7.       
    8.     @RequestMapping("")  
    9.     public String doTask() throws InterruptedException{  
    10.         long currentTimeMillis = System.currentTimeMillis();  
    11.         Future<String> task1 = asyncTask.task1();  
    12.         Future<String> task2 = asyncTask.task2();  
    13.         Future<String> task3 = asyncTask.task3();  
    14.         String result = null;  
    15.         for (;;) {  
    16.             if(task1.isDone() && task2.isDone() && task3.isDone()) {  
    17.                 // 三个任务都调用完成,退出循环等待  
    18.                 break;  
    19.             }  
    20.             Thread.sleep(1000);  
    21.         }  
    22.         long currentTimeMillis1 = System.currentTimeMillis();  
    23.         result = "task任务总耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms";  
    24.         return result;  
    25.     }  
    26. }  

    控制台输出:

    [html] view plain copy
     
    1. task1任务耗时:1000ms  
    2. task2任务耗时:2001ms  
    3. task3任务耗时:3001ms  

    浏览器输出:

    [html] view plain copy
     
    1. <span style="font-family: Simsun; font-size: 14px;">task任务总耗时:4015ms</span>  
     

    异步调用成功,并且在所有任务都完成时程序才返回了结果!

  • 相关阅读:
    [JavaScript]Cookie详解(转)
    C#中一些默认的预定义特性
    Web 设计与开发终极资源大全
    C# FileStream 文件读写(转)
    使用Jsonp解决跨域数据访问问题[转]
    针对未安装 adobe flash activex 插件 的 ie 浏览器 自动提示安装
    IE position:relative bug
    linux磁盘操作之sgdisk
    安装 archlinux 之使用 EFI/GPT
    从今开始,多花点时间研究技术
  • 原文地址:https://www.cnblogs.com/shihaiming/p/7825204.html
Copyright © 2020-2023  润新知