开发者学堂课程【SpringBoot 实战教程:异步调用】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/651/detail/10793
异步调用
内容介绍:
一、定义
二、演示
一、定义
在项目中,难免会调用第三方接口,当访问其它接口较慢或者做耗时任务时,不想程序一直卡在耗时任务上,想程序能够并行执行,可以使用多线程来并行的处理任务,SpringBoot 提供了异步处理方式@Async。
二、演示
1、写一个功能,功能定义在 Service 中,创建一个 Service 的包。写一个接口,命名为 asyncService。可以多写几个功能,效果明显。
@Service 创建实例
public class AsyncServiceImpl implements AsyncService {
public static Random random =new Random() ;
睡的时间随机生成
@Async 让它单独开始子线程,只需要加上这个注解即可,异步执行
@Override
public Future<string> doTask1() throws ;Exception {
System. out. println ("
任务一开始执行
");
打印表示开始执行
long start = System. currentTimeMi
l
lis() ;
记录开始时间
Thread. sleep ( random. nextInt (10000)) ;
为了体现它的耗时,让它单独开启的线程睡眠
long end = System. currentTimeMi
l
lis() ;
记录结束时间
System. out. println("
任务一结束
,
耗时
: " + (end - start) + "
毫秒
") ;
return new AsyncResult<> ("
任务完成
") ;
用它的子类,它是future具体的子类,另外两个功能也是一样。
@Async
@Override
public Future<String> doTask2 () throws Exception
{
System. out.println ("(
任务二开始执行
") ;
Long
start=System. currentTimeMi
l
lis() ;
Thread. sleep( random. nextInt (10000) ) ;
Long
end = System. currentTimeMil
l
is() ;
System. out.println("
任务二结束
,
耗时
:
"+ (end-start) +"
毫秒
") ;
return new AsyncResult<> ("
任务二结束
") ;
}
@Async
@Override
public Future<String> doTask3() 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<> ("(
任务三结束
") ;
}
}
2、在 controller 中调用这三个功能,要调用 service 功能,所以把 service 进行注入。统计三个功能全部执行完耗时多长,先记录开始时间,调用三个功能时,它们会各自开启一个线程,这时会有三个相应的子线程,加上当前的主线程,需要反复判断三个功能什么时候耗时完。
@Controller
public class TestController
{
@Autowired
private AsyncService
asyncService ;
@RequestMapping ("/ show")
@ResponseBody
Public
String show ( )
{
/ /int
a = 5/0;
int[]arr
=
new
int[3] ;
System. out.println(arr[3]) ;
Return
"show" ;
}
@RequestMapping ("/async")
@ResponseBody
public String asyncTest ( )throws Exception
{
Long
start = System. currentTimeMi
l
lis();
记录开始时间
Future<String> task1=asyncService .doTask1() ;
提供线程是否结束的功能
Future<String> task2=asyncService .doTask2 () ;
Future<String> task3=asyncService .doTask3() ;
while ( true )
{
if (task1. isDone () && task2 . isDone () && task3. isDone () )
用这个方法进行判断,如果三个线程都结束了
{
break;
while循环也结束
}
Thread. sleep(1000) ;
反复判断,连续计算它可能一直不结束,所以可以让当前的线程休息后再去判断
Long
end = System. currentTimeMi
l
lis();
记录结束时间
return"全部执行完成,总耗时: "+ (end-start) +;"毫秒
"
;
}
这是在 Controller 中调用三个异步执行的功能。
3、@EnableAsync
//开启异步调用
在启动类中指明异步执行,希望在子线程中执行的功能,要加上async注解,但是还要在启动类中加开启异步调用的注解。service也需要扫描,所以要加上service的包“com. qianfeng .controller", "com. qianfeng. service"
4、返回的是 responsebody,最后返回return”全部执行完成,总耗时:"'+ (end-start) +"毫秒;
5、启动,访问路径 async,全部执行完成,总耗时7084毫秒。
6、可以看到控制台的打印,任务一,二,三,开始,结束时间就不是一二三的顺序,结束是三一二,多线程的执行结果是不确定的,先开启的不一定先结束。