一般我们在使用@Async注解的时候,其注解的方法是不带返回值的,不过有的时候,某些功能可能需要我们异步调用且获得返回值。
被@Async注解的方法,返回值类型需要是Future<T>类型,所以需要写一个Future<T>的实现类,用于做异步调用方法的返回。
public class AsyncResult<V> implements Future<V> {
private final V value;
public AsyncResult(V value) {
this.value = value;
}
public boolean cancel(boolean mayInterruptIfRunning) {
return false;
}
public boolean isCancelled() {
return false;
}
public boolean isDone() {
return true;
}
public V get() {
return this.value;
}
public V get(long timeout, TimeUnit unit) {
return this.value;
}
}
假设我们在一个方法里想要异步调用好几个方法,获得它们的返回值然后进行下步操作,那么多个调用的延迟是怎样的的呢?我们写些代码测试一下
测试使用springboot框架,版本是2.0.0RELEASE
先写一个service
@Slf4j
@Service
public class TestService {
@Async
public Future<String> testReturnA(){
log.info("serviceA: " + Thread.currentThread().getName() + " tid: " + Thread.currentThread().getId());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AsyncResult<>("testA");
}
@Async
public Future<String> testReturnB(){
log.info("serviceB: " + Thread.currentThread().getName() + " tid: " + Thread.currentThread().getId());
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new AsyncResult<>("testB");
}
}
再写一个controller,test1和test2分别有不同的异步调用顺序
@Slf4j
@RequestMapping
@RestController
public class TestController {
@Resource
TestService testService;
@GetMapping("/test1")
public String test1() {
log.info("controller 1: " + Thread.currentThread().getName() + " tid: " + Thread.currentThread().getId());
Future<String> futureA = testService.testReturnA();
Future<String> futureB = testService.testReturnB();
try {
String a = futureA.get();
String b = futureB.get();
log.info("controller1 asyn finishes");
return a + "-" + b;
} catch (Exception e) {
log.error(e.getMessage(), e);
return "error";
}
}
@GetMapping("/test2")
public String test2() {
log.info("controller2: " + Thread.currentThread().getName() + " tid: " + Thread.currentThread().getId());
Future<String> futureA = testService.testReturnA();
Future<String> futureB = testService.testReturnB();
try {
String b = futureB.get();
String a = futureA.get();
log.info("controller2 asyn finishes");
return a + "-" + b;
} catch (Exception e) {
log.error(e.getMessage(), e);
return "error";
}
}
}
本地启动,浏览器分别调用http://localhost:8080/test1和http://localhost:8080/test2,均能成功返回“testA-testB”
日志打印如下
2020-04-29 12:18:06.912 INFO 20408 --- [nio-8080-exec-2] c.e.boottest.controller.TestController : controller 1: http-nio-8080-exec-2 tid: 33
2020-04-29 12:18:06.926 INFO 20408 --- [ task-1] c.example.boottest.service.TestService : serviceA: task-1 tid: 52
2020-04-29 12:18:06.926 INFO 20408 --- [ task-2] c.example.boottest.service.TestService : serviceB: task-2 tid: 53
2020-04-29 12:18:11.926 INFO 20408 --- [nio-8080-exec-2] c.e.boottest.controller.TestController : controller1 asyn finishes
2020-04-29 12:18:23.395 INFO 20408 --- [nio-8080-exec-1] c.e.boottest.controller.TestController : controller2: http-nio-8080-exec-1 tid: 32
2020-04-29 12:18:23.396 INFO 20408 --- [ task-3] c.example.boottest.service.TestService : serviceA: task-3 tid: 54
2020-04-29 12:18:23.397 INFO 20408 --- [ task-4] c.example.boottest.service.TestService : serviceB: task-4 tid: 55
2020-04-29 12:18:28.398 INFO 20408 --- [nio-8080-exec-1] c.e.boottest.controller.TestController : controller2 asyn finishes
可以发现时延迟都是5秒,所以多个异步调用,总时延是多个异步调用时延的最大值
网友评论