什么是异步调用?

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

如何实现异步调用?

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

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

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

按照官方示例开撸

代码入下

maven依赖:

  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注解

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

Controller 

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

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

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

http://localhost:8080/

控制台:

  1. task1任务耗时:1012ms
  2. task2任务耗时:2009ms
  3. task3任务耗时:3004ms
 

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

  1. task任务总耗时:6002ms

异步并没有执行!

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

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

Controller

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

异步任务类

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

控制台:

  1. task1任务耗时:1012ms
  2. task2任务耗时:2009ms
  3. task3任务耗时:3004ms

访问浏览器结果入下:

  1. task任务总耗时:19ms
 

异步调用成功!

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

代码入下:

异步任务类

  1. @Component
  2. public class AsyncTask {
  3. @Async
  4. public Future<String> task1() throws InterruptedException{
  5. long currentTimeMillis = System.currentTimeMillis();
  6. Thread.sleep(1000);
  7. long currentTimeMillis1 = System.currentTimeMillis();
  8. System.out.println("task1任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
  9. return new AsyncResult<String>("task1执行完毕");
  10. }
  11. @Async
  12. public Future<String> task2() throws InterruptedException{
  13. long currentTimeMillis = System.currentTimeMillis();
  14. Thread.sleep(2000);
  15. long currentTimeMillis1 = System.currentTimeMillis();
  16. System.out.println("task2任务耗时:"+(currentTimeMillis1-currentTimeMillis)+"ms");
  17. return new AsyncResult<String>("task2执行完毕");
  18. }
  19. @Async
  20. public Future<String> 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. return new AsyncResult<String>("task3执行完毕");
  26. }
  27. }

Controller

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

控制台输出:

  1. task1任务耗时:1000ms
  2. task2任务耗时:2001ms
  3. task3任务耗时:3001ms

浏览器输出:

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

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

版权声明:本文为博主原创文章,未经博主允许不得转载。

SpringBoot集成篇(二) 异步调用Async的更多相关文章

  1. springboot:异步调用@Async

    在后端开发中经常遇到一些耗时或者第三方系统调用的情况,我们知道Java程序一般的执行流程是顺序执行(不考虑多线程并发的情况),但是顺序执行的效率肯定是无法达到我们的预期的,这时就期望可以并行执行,常规 ...

  2. SpringBoot学习笔记(七):SpringBoot使用AOP统一处理请求日志、SpringBoot定时任务@Scheduled、SpringBoot异步调用Async、自定义参数

    SpringBoot使用AOP统一处理请求日志 这里就提到了我们Spring当中的AOP,也就是面向切面编程,今天我们使用AOP去对我们的所有请求进行一个统一处理.首先在pom.xml中引入我们需要的 ...

  3. springboot:嵌套使用异步注解@Async还会异步执行吗

    一.引言 在前边的文章<[springboot:使用异步注解@Async的那些坑>中介绍了使用@Async注解获取任务执行结果的错误用法,今天来分享下另外一种常见的错误. 二.代码演示 下 ...

  4. SpringBoot系列:Spring Boot异步调用@Async

    在实际开发中,有时候为了及时处理请求和进行响应,我们可能会多任务同时执行,或者先处理主任务,也就是异步调用,异步调用的实现有很多,例如多线程.定时任务.消息队列等, 这一章节,我们就来讲讲@Async ...

  5. springboot 异步调用Async使用方法

    引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交互的时候,容易造成响应迟缓的情况,之前大部分都是使用多线程来完成此类任务,其实,在spring 3. ...

  6. springboot之异步调用@Async

    原文:http://www.cnblogs.com/xuwenjin/p/8858050.html 引言: 在Java应用中,绝大多数情况下都是通过同步的方式来实现交互处理的:但是在处理与第三方系统交 ...

  7. 170719、springboot编程之异步调用@Async

    1.在pom.xml中增加依赖 <dependency> <groupId>org.springframework.boot</groupId> <artif ...

  8. SpringBoot异步调用--@Async详解

    1. 概述   在日常开发中,为了提高主线程的效率,往往需要采用异步调用处理,例如系统日志等.在实际业务场景中,可以使用消息中间件如RabbitMQ.RocketMQ.Kafka等来解决.假如对高可用 ...

  9. nodejs异步调用async

    犹豫nodejs是异步编程模型,有一些在同步编程中很容易做到的事情,现在却变得很麻烦,async的流程控制就是为了简化这些操作var async = require('async'); 1.serie ...

随机推荐

  1. html:模板

    http://www.mycodes.net/code_previewmap.php?id=3461 http://www.17sucai.com/pins/4120.html  欧美风格的CMS企业 ...

  2. aix系统使用随笔

    在 Aix操作系统 中,常用的文档编辑命令是 vi.下面,我们就来学习一下有关vi的使用决窍. 在vi中,必须牢记它是有两个状态的 ---- 输入状态与命令状态.由输入状态切换 到命令状态,必须ESC ...

  3. eclipse运行程序时报java.lang.OutOfMemoryError: Java heap space内存不足问题

    System.setProperty("webdriver.firefox.bin", "D:\\Mozilla Firefox\\firefox.exe"); ...

  4. maven的小知识

    一.下载及安装 1.1 下载maven 3.1.1 先到官网http://maven.apache.org/download.cgi 下载最新版本(目前是3.1.1 ),下载完成后,解压到某个目录(本 ...

  5. VBA 判断单元格是否为公式,可用于数组

    Function ISFORMULA(ByVal rg As Object) As Variant      Dim temp As Variant      Dim i As Integer, j ...

  6. 相对固定位置 relative absolute

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  7. C#连接sqlserver windows 和 sqlserver 身份验证的两种连接字符串

    //sql server 身份验证 连接字符串 private string ConnstrSqlServer = "server=服务器名称;uid=登录名称;pwd=登录密码;datab ...

  8. 面试题-------SSL协议简介

    SSL协议简介 SSL简介 Secure Socket Layer,为Netscape所研发,用以保障在Internet上数据传输之安全,利用数据加密(Encryption)技术,可确保数据在网络上之 ...

  9. 转载:mysql数据同步redis

    from: http://www.cnblogs.com/zhxilin/archive/2016/09/30/5923671.html 在服务端开发过程中,一般会使用MySQL等关系型数据库作为最终 ...

  10. ubuntu安装openssh-server 报依赖错误的解决过程

    ubuntu自带的有openssh-client,所以可以通过 ? 1 ssh username@host 来远程连接linux 可是要想通过ssh被连接,ubuntu系统需要有openssh-ser ...