Spring @Async之一:实现异步调用示例
什么是“异步调用”?
“异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。
同步调用
下面通过一个简单示例来直观的理解什么是同步调用:
定义Task类,创建三个处理函数分别模拟三个执行任务的操作,操作消耗时间随机取(10秒内)
package com.dxz.demo1; import java.util.Random;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping; /**
* 定义3个任务
*/
@Component
public class Task1 { // 定义一个随机对象.
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) + "毫秒");
} // 任务3;
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) + "毫秒");
} }
编写一个访问方法:
package com.dxz.demo1; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import com.dxz.HelloApplication; @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = HelloApplication.class)
public class Task1Test { @Autowired
private Task1 task1; //测试task1.
@Test
public void task1() throws Exception{
task1.doTaskOne();
task1.doTaskTwo();
task1.doTaskThree();
}
}
运行可以看到类似如下输出:
开始做任务一
2017-04-28 18:02:57.397 WARN 11016 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:02:57.398 INFO 11016 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
完成任务一,耗时:7740毫秒
开始做任务二
完成任务二,耗时:723毫秒
开始做任务三
2017-04-28 18:03:03.415 WARN 11016 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:03:03.415 INFO 11016 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
完成任务三,耗时:5047毫秒
异步调用
上述的同步调用虽然顺利的执行完了三个任务,但是可以看到执行时间比较长,若这三个任务本身之间不存在依赖关系,可以并发执行的话,同步调用在执行效率方面就比较差,可以考虑通过异步调用的方式来并发执行。
在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数,Task类改在为如下模式:
package com.dxz.demo1; import java.util.Random; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping; /**
* 定义3个任务
*/
@Component
public class Task2 { // 定义一个随机对象.
public static Random random = new Random(); // 任务一;
@Async
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) + "毫秒");
} // 任务二;
@Async
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) + "毫秒");
} // 任务3;
@Async
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) + "毫秒");
} }
为了让@Async注解能够生效,还需要在Spring Boot的主程序中配置@EnableAsync,如下所示:
package com.dxz; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;
@EnableAsync
@SpringBootApplication
public class HelloApplication {
public static void main(String[] args) {
SpringApplication.run(HelloApplication.class, args);
}
}
编写测试方法:
package com.dxz.demo1; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping; import com.dxz.HelloApplication; @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = HelloApplication.class)
public class Task2Test { @Autowired
private Task2 task2; //测试task1.
@Test
public void task1() throws Exception{
task2.doTaskOne();
task2.doTaskTwo();
task2.doTaskThree();
}
}
此时可以反复执行单元测试,您可能会遇到各种不同的结果,比如:
开始做任务一
开始做任务二
开始做任务三
修改下测试类:
package com.dxz.demo1; import java.util.concurrent.TimeUnit; import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.SpringApplicationConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.web.bind.annotation.RequestMapping; import com.dxz.HelloApplication; @RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = HelloApplication.class)
public class Task2Test { @Autowired
private Task2 task2; // 测试task1.
@Test
public void task1() throws Exception {
task2.doTaskOne();
task2.doTaskTwo();
task2.doTaskThree(); System.out.println("i'm here");
TimeUnit.SECONDS.sleep(15);
System.out.println("over");
} }
jieguo:
i'm here
开始做任务二
开始做任务一
开始做任务三
完成任务三,耗时:1280毫秒
2017-04-28 18:25:36.936 WARN 17848 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:25:36.938 INFO 17848 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
完成任务一,耗时:4951毫秒
完成任务二,耗时:7451毫秒
2017-04-28 18:25:42.971 WARN 17848 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Consumer raised exception, processing can restart if the connection factory supports it. Exception summary: org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-04-28 18:25:42.972 INFO 17848 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Restarting Consumer: tags=[{}], channel=null, acknowledgeMode=AUTO local queue size=0
over
Spring @Async之一:实现异步调用示例的更多相关文章
- SpringBoot系列——@Async优雅的异步调用
前言 众所周知,java的代码是同步顺序执行,当我们需要执行异步操作时我们需要创建一个新线程去执行,以往我们是这样操作的: /** * 任务类 */ class Task implements Run ...
- C#中异步调用示例与详解
using System; using System.Collections.Generic; using System.Text; using System.Runtime.InteropServi ...
- Spring @Async实现异步调用示例
什么是“异步调用”? “异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行:异步调用指程序在顺序执行时,不等待异步调用的语句返回结果 ...
- Spring Boot中实现异步调用之@Async
一.什么是异步调用 “异步调用”对应的是“同步调用”,同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行:异步调用指程序在顺序执行时,不等待异步调用 的语句返回结果 ...
- 使用Spring中@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@Async注解实现异步方法调用
概述 如何实现异步方法调用,很多人首先会想到使用线程或者线程池技术,springboot中有一个很简单的方法可以实现异步方法调用,那就是在方法上使用@Async注解 例子 首先在Springboot启 ...
- 【Spring Boot学习之六】Spring Boot整合定时任务&异步调用
环境 eclipse 4.7 jdk 1.8 Spring Boot 1.5.2一.定时任务1.启动类添加注解@EnableScheduling 用于开启定时任务 package com.wjy; i ...
随机推荐
- [C++_QT] 同步方式提交GET和POST请求
#开始 最近在做一个需要用到提交HTTP请求的工具 但是遇到一个问题 如下 在Qt中提交一个get请求之后(或者post) 在收到回复之后会调用之前连接好的槽函数 但是问题就是在主调函数中不知道什么时 ...
- 《实战Java高并发程序设计》读书笔记三
第三章 JDK并发包 1.同步控制 重入锁:重入锁使用java.util.concurrent.locks.ReentrantLock类来实现,这种锁可以反复使用所以叫重入锁. 重入锁和synchro ...
- Spring的事务实现原理
主流程 Spring的事务采用AOP的方式实现. @Transactional 注解的属性信息 name 当在配置文件中有多个 TransactionManager , ...
- 迷のbug
已解决(ps over%100写错了,应该是over/100...) #include <bits/stdc++.h> #define rep(i, a, b) for(int i = a ...
- C++基础之迭代器iterator
C++基础之迭代器iterator 我们已经知道可以使用下标运算符来访问string对象的字符或vector对象的元素,还有另一种更通用的机制也可以实现同样的目的,这就是迭代器(iterator). ...
- Django rest framework框架中有哪些组件
认证 权限(授权) 用户访问次数/频率限制 版本 解析器(parser) 序列化 分页 路由系统 视图 渲染器 认证 自定义认证的类 """ from rest_fram ...
- FTP 上传下载 进度条
11 /// <summary> /// 文件上传 /// </summary> /// <param name="filePath">原路径( ...
- 5G时代开启,这些新兴职业决定你的后半生
近段时间,高考志愿填报成为牵动千万家庭的头等大事.事实上,除了学校间的差距外,专业的优劣也在很大程度上决定着人们未来职场生涯的潜力.血淋淋的事实告诉我们,只有选对专业,才能让自己的人生实现升华,并避免 ...
- mcast_unblock_source函数
#include <errno.h> #include <sys/socket.h> #define SA struct sockaddr int mcast_unblock_ ...
- Python基础入门语法1
PY的交换值的方法 x.y = y.x PY既具有动态脚本的特性,又有面向对象的特性 PY的缺点: 编译型的语言(C++,C):通过编译器进行编译成机器码,越接近底层,开发效率低 解释型代码:PY和J ...