概念
- 同步调用:同步调用指程序按照定义顺序依次执行,每一行程序都必须等待上一行程序执行完成之后才能执行;
- 异步调用:异步调用指程序在顺序执行时,不等待异步调用的语句返回结果就执行后面的程序。
异步调用
- 在Spring Boot中,可以通过使用
@Async
注解就能简单的将原来的同步函数变为异步函数; - 主程序在异步调用之后,主程序并不会理会异步函数是否执行完成了,由于没有其他需要执行的内容,所以程序就自动结束了,导致了不完整或是没有输出任务相关内容的情况。
异步回调
- 为了让异步函数都能正常结束,我们需要判断异步调用是否以及执行完成,可以使用
Future<T>
来返回异步调用的结果。示例如下:
@Component
public class Task {
public static Random random =new Random();
@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<>("任务一完成");
}
@Async
public Future<String> doTaskTwo() 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<>("任务二完成");
}
@Async
public Future<String> doTaskThree() 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<>("任务三完成");
}
}
注:@Async
所修饰的函数不要定义为static类型,这样异步调用不会生效
- 为了让
@Async
注解能够生效,还需在Spring Boot的主程序中配置@EnableAsync
,如下:
@SpringBootApplication
@EnableAsync
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
- 测试用例
@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) + "毫秒");
}