Spring Boot中实现异步调用之@Async
一、什么是异步调用
“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用
的语句返回结果就执行后面的程序。
二、同步调用
下面通过一个简单示例来直观的理解什么是同步调用:
定义Task类,创建三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10秒内)
@Component
public class Task { public static Random random =new Random(); public void doTaskOne() throws Exception {
System.out.println("开始做任务一");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
} public void doTaskTwo() throws Exception {
System.out.println("开始做任务二");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务二,耗时:" + (end - start) + "毫秒");
} public void doTaskThree() throws Exception {
System.out.println("开始做任务三");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务三,耗时:" + (end - start) + "毫秒");
} }
在单元测试用例中,注入Task对象,并在测试用例中执行doTaskOne
、doTaskTwo
、doTaskThree
三个函数。
@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = Application.class)
public class ApplicationTests {
@Autowired
private Task task; @Test
public void test() throws Exception {
task.doTaskOne();
task.doTaskTwo();
task.doTaskThree();
}
}
执行单元测试,可以看到类似如下输出:
开始做任务一
完成任务一,耗时:4256毫秒
开始做任务二
完成任务二,耗时:4957毫秒
开始做任务三
完成任务三,耗时:7173毫秒
任务一、任务二、任务三顺序的执行完了,换言之doTaskOne
、doTaskTwo
、doTaskThree
三个函数顺序的执行完成。
三、异步调用
上述的同步调用虽然顺利的执行完了三个任务,但是可以看到执行时间比较长,若这三个任务本身之间不存在依赖关系,可以并发执行的话,同步调用在执行效率方面就比较差,可以
考虑通过异步调用的方式来并发执行。
在Spring Boot中,我们只需要通过使用@Async
注解就能简单的将原来的同步函数变为异步函数,Task类改在为如下模式:
@Component
public class Task {
@Async
public void doTaskOne() throws Exception {
// 同上内容,省略
}
@Async
public void doTaskTwo() throws Exception {
// 同上内容,省略
}
@Async
public void doTaskThree() throws Exception {
// 同上内容,省略
}
}
为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示:
@SpringBootApplication
@EnableAsync
public class Application { public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} }
此时可以反复执行单元测试,您可能会遇到各种不同的结果,比如:
(1)没有任何任务相关的输出
(2)有部分任务相关的输出
(3)乱序的任务相关的输出
原因是目前doTaskOne
、doTaskTwo
、doTaskThree
三个函数的时候已经是异步执行了。主程序在异步调用之后,主程序并不会理会这三个函数是否执行完成了,由于
没有其他需要执行的内容,所以程序就自动结束了,导致了不完整或是没有输出任务相关内容的情况。
注: @Async所修饰的函数不要定义为static类型,这样异步调用不会生效
四、异步回调
为了让doTaskOne
、doTaskTwo
、doTaskThree
能正常结束,假设我们需要统计一下三个任务并发执行共耗时多少,这就需要等到上述三个函数都完成调动之后记录时间,
并计算结果。
那么我们如何判断上述三个异步调用是否已经执行完成呢?我们需要使用Future<T>
来返回异步调用的结果,就像如下方式改造doTaskOne
函数:
@Async
public Future<String> doTaskOne() throws Exception {
System.out.println("开始做任务一");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
System.out.println("完成任务一,耗时:" + (end - start) + "毫秒");
return new AsyncResult<>("任务一完成");
}
按照如上方式改造一下其他两个异步函数之后,下面我们改造一下测试用例,让测试在等待完成三个异步调用之后来做一些其他事情。
@Test
public void test() throws Exception {
long start = System.currentTimeMillis();
Future<String> task1 = task.doTaskOne();
Future<String> task2 = task.doTaskTwo();
Future<String> task3 = task.doTaskThree();
while(true) {
if(task1.isDone() && task2.isDone() && task3.isDone()) {
// 三个任务都调用完成,退出循环等待
break;
}
Thread.sleep(1000);
}
long end = System.currentTimeMillis();
System.out.println("任务全部完成,总耗时:" + (end - start) + "毫秒");
}
转载自:http://blog.didispace.com/springbootasync/
Spring Boot中实现异步调用之@Async的更多相关文章
- (转)spring boot注解 --@EnableAsync 异步调用
原文:http://www.cnblogs.com/azhqiang/p/5609615.html EnableAsync注解的意思是可以异步执行,就是开启多线程的意思.可以标注在方法.类上. @Co ...
- spring boot注解 --@EnableAsync 异步调用
EnableAsync注解的意思是可以异步执行,就是开启多线程的意思.可以标注在方法.类上. @Component public class Task { @Async public void doT ...
- 【Spring Boot学习之六】Spring Boot整合定时任务&异步调用
环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2一.定时任务1.启动类添加注解@EnableScheduling 用于开启定时任务 package com.wjy; i ...
- 如何在项目中使用Spring异步调用注解@Async
本文主要介绍如何使用Spring框架提供的异步调用注解@Async,异步线程池配置.异常捕获处理. 开启@Async注解支持 使用@Async注解的之前,必须在项目中启动时调用@EnableAsync ...
- Spring Boot 中如何支持异步方法
本人免费整理了Java高级资料,涵盖了Java.Redis.MongoDB.MySQL.Zookeeper.Spring Cloud.Dubbo高并发分布式等教程,一共30G,需要自己领取.传送门:h ...
- spring boot中使用@Async实现异步调用任务
本篇文章主要介绍了spring boot中使用@Async实现异步调用任务,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 什么是“异步调用”? “异步调用”对应的是“同步 ...
- Spring Boot中使用@Async实现异步调用
在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数,为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsyn ...
- 56. spring boot中使用@Async实现异步调用【从零开始学Spring Boot】
什么是"异步调用"? "异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执 ...
- Spring Boot中使用@Async实现异步调用,加速任务的执行!
什么是"异步调用"?"异步调用"对应的是"同步调用",同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行 ...
随机推荐
- Job for docker.service failed because the control process exited with error code. See "systemctl status docker.service" and "journalctl -xe" for details.
文档:Docker 启动错误.note链接:http://note.youdao.com/noteshare?id=065111d506e1b132dc930dbe88f5d7b0&sub=A ...
- ARM CORTEX-M3的时钟
转载自:http://www.cnblogs.com/javado/p/7704579.html 这几天写了一段测试代码,跑在LPC812上面. 很吃惊的发现CPU速度为1M 时钟 串口为12M时钟 ...
- MySQL使用yum安装
1.下载mysql的repo源 $ wget http://repo.mysql.com/mysql-community-release-el7-5.noarch.rpm 2.安装mysql-comm ...
- loj2032 「SDOI2016」游戏
做了 [JSOI2008]Blue Mary开公司 以后发现这 tm 不就是个傻逼树剖+李超线段树吗,做了以后发现我才是傻逼--树剖竟然写错了--这题是我目前写过最长的代码了qwq #include ...
- 0016.Linux基础之常用基本命令讲解
开启linux系统,开启xshell pwd:printing workding directory 打印当前目录 /:代表根目录 cd:change directory 改变目录 ls:list 查 ...
- 忘记MySQL的root密码的解决方法
经常会有朋友或者同事问起,MySQL 的 root 密码忘了,不知道改怎么办. 其实解决方法很简单,下面是详细的操作步骤. (1)修改配置文件my.cnf,在配置文件[mysqld]下添加skip-g ...
- [python][oldboy]list append, extend
# coding=utf8 li = [1, 3, [1, "liu"], "liu"] print li li.append([1, 2]) print li ...
- hdu5441
Travel Time Limit: 1500/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total Su ...
- POJ 1145 Tree Summing
Tree Summing Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 7698 Accepted: 1737 Desc ...
- POJ 2051 Argus
Argus Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 8782 Accepted: 3985 Description ...