SpringBoot2 | 第二十四篇(一):使用@Async实现异步调用

什么是“异步调用”?

​ “异步调用”对应的是“同步调用”,同步调用 指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;异步调用 指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。

[TOC]

@Async

​ 在Spring中,基于@Async 标注的方法,称之为 异步方法;这些方法将在执行的时候,将会在独立的线程中被执行,调用者无需等待它的完成,即可继续其他的操作。在Spring Boot中,我们只需要通过使用@Async注解就能简单的将原来的同步函数变为异步函数。

环境/版本一览:

  • 开发工具:Intellij IDEA 2018.2.2
  • springboot: 2.0.6.RELEASE
  • jdk:1.8.0_171
  • maven:3.3.9

1、pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
</dependency>
</dependencies>

2、component

Task组件 的异步方法中使用Future<String>作为返回类型,通过调用 isDone() 方法来达到判断异步方法是否执行成功的效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
package com.fatal.component;

import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Component;

import java.util.Random;
import java.util.concurrent.Future;

/**
* 测试异步注解@Async的组件
* @author: Fatal
* @date: 2018/10/31 0031 9:47
*/
@Slf4j
@Component
public class Task {

public static Random random = new Random();

@Async
public Future<String> doTaskOne() throws Exception {
log.info("[----------开始执行任务]");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("[----------执行任务完成] 耗时:" + (end-start) + "毫秒");
return new AsyncResult<>("----------完成任务");
}

@Async
public Future<String> doTaskTwo() throws Exception {
log.info("[++++++++++开始执行任务]");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("[++++++++++执行任务完成] 耗时:" + (end-start) + "毫秒");
return new AsyncResult<>("++++++++++完成任务");
}

@Async
public Future<String> doTaskThree() throws Exception {
log.info("[**********开始执行任务]");
long start = System.currentTimeMillis();
Thread.sleep(random.nextInt(10000));
long end = System.currentTimeMillis();
log.info("[**********执行任务完成] 耗时:" + (end-start) + "毫秒");
return new AsyncResult<>("**********完成任务");
}

}

3、Application

在配置类上加上@EnableAsync打开异步功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.fatal;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableAsync;

@EnableAsync
@SpringBootApplication
public class Chapter241Application {

public static void main(String[] args) {
SpringApplication.run(Chapter241Application.class, args);
}
}

4、Test

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package com.fatal;

import com.fatal.component.Task;
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.util.concurrent.Future;

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class Chapter241ApplicationTests {

@Autowired
private Task task;

@Test
public void contextLoads() throws Exception {
Future<String> taskOne = task.doTaskOne();
Future<String> taskTwo = task.doTaskTwo();
Future<String> taskThree = task.doTaskThree();
long start = System.currentTimeMillis();
while (true) {
// 判断异步方法是否执行完成
if (taskOne.isDone() && taskTwo.isDone() && taskThree.isDone()) {
break;
}
}
long end = System.currentTimeMillis();
log.info("任务全部完成,总耗时:" + (end - start) + "毫秒");
}

}

5、显示

执行 Chapter241ApplicationTests.contextLoads() 方法显示

1540953744818

可以看到,通过异步调用,让任务一、二、三并发执行,有效的减少了程序的总运行时间

参考资料

Spring Boot中使用@Async实现异步调用

总结

步骤:

  1. 在方法上加上 @Async
  2. 在配置类(启动类也属于配置类)上加上 @EnableAsync

SpringBoot的知识已经有前辈在我们之前探索了。比较喜欢的博主有:唐亚峰 | Battcn方志朋的专栏程序猿DD纯洁的微笑。对这门技术感兴趣的可以去他们的博客逛逛。谢谢他们的分享~~

以上文章是我用来学习的Demo,都是基于 SpringBoot2.x 版本。

源码地址: https://github.com/ynfatal/springboot2-learning/tree/master/chapter24_1

学习 翟永超 前辈的经验