什么是异步调用?

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

如何实现异步调用?

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

在非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. 2.纯 CSS 创作一个矩形旋转 loader 特效

    原文地址:2.纯 CSS 创作一个矩形旋转 loader 特效 扩展后地址:https://scrimba.com/c/cNJVWUR  扩展地址:https://codepen.io/pen/ HT ...

  2. PHP获取照片exif信息

    在这个没图说个屁的年代,照片还是很重要的.如果照片上传后会自动加上 照片相关信息,那用户体验的确会好很多,本着这个想法,今天尝试了下 PHP获取照片exif信息,重要的是 获取图片的GPS信息,如果再 ...

  3. Xshell使用

    xshell更新之后窗口标题没了,多个窗口之后没法切换. 使用ctrl+shift+t恢复 ¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥

  4. Firemonkey 绘图 TPathData

    Firemonkey  TPathData TPath控件 procedure TForm12.FormPaint( Sender : TObject; Canvas : TCanvas; const ...

  5. 进程和创建线程的两种方法(threading.Thread)

    进程 如QQ 要以一个整体的形式暴露给操作系统管理,里面包含对各种资源的调用,内存的管理, 网络接口的调用等,进程就是各种资源管理的集合 线程:是操作系统最小的调度单位,是一串指令的结合 进程 要操作 ...

  6. UI5-文档-4-Walkthrough

    在本教程中,我们将向您介绍SAPUI5的所有主要开发范例. 我们首先向您介绍基本的开发范例,如模型M-视图V-控制器C,并为我们的应用程序建立一个最佳实践结构.我们将以经典的“Hello World” ...

  7. nginx访问静态文件配置

    通过nginx访问静态文件配置,均是在server模块中配置,有两种方式: 1.alias 通过alias关键字,重定义路径,如 server{     listen 7001;     server ...

  8. 在Linux Bash通过上下键快速查找历史命令

    在centos 7中 ~/.bashrc 或者Mac中的 ~/.bash_profile 中添加,然后source一下以下内容: if [[ $- == *i* ]] then bind '" ...

  9. 类定义,创建/销毁OC对象

    类定义 1 OC类分为2个文件,一个是.h文件,一个是.m文件: 2 .h文件存放类.函数声明: 3 .m文件类的具体实现: 4 类声明使用关键字@interface.@end来声明: 5 类实现使用 ...

  10. redis启动.停止.重启

    Linux下安装 ]# wget http://download.redis.io/releases/redis-2.8.17.tar.gz ]# tar xzf redis-2.8.17.tar.g ...