背景
被调用的各微服务不存在性能问题,每个微服务调用时间长短不一,且没有优化的空间;此外,排除网络IO的影响,排除微服务所在物理机性能差异。
思路
-
面试题官已经提示很明确了,将原来主方法中同步调用各微服务改为异步调用即可。
-
那么问题来了,改为异步调用后,如何保证所有微服务方法调用完毕后,拿到各个返回值统一包装返回给到客户端?
-
这里其实考察的就是你对并发编程的掌握程度以及有没有实际的开发经验。
实现
1、Java5引入了Future和 FutureTask,用于异步处理。Future可以通过get()方法获取异步的返回值。 2、在Java8引入了CompletableFuture,CompletableFuture不仅实现了Future接口, 还实现了CompletionStage接口。 3、CompletableFuture实现了CompletionStage接口,重写thenApply()、thenCombine()等方法。 4、CompletableFuture类能够处理多个异步任务,还能处理异步回调。
话不多说,直接上代码。
public class TestThread {
public static void main(String[] args) throws InterruptedException {
test2();
}
public static void test2(){
//这里只是示例,实际不推荐Executors直接创建线程池。
ExecutorService executorService = Executors.newCachedThreadPool();
CompletableFuture<String> cf1 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务1开始!");
try {
Thread.sleep(6000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println("任务1结束!");
return "11";
},executorService);
CompletableFuture<String> cf2 = CompletableFuture.supplyAsync(() -> {
System.out.println("任务2结束!");
return "22";
},executorService);
String result1 = "";
try {
result1 = cf1.get(7, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
throw new RuntimeException(e);
}
System.out.println("get result1 : " + result1);
String result2 = "";
try {
result2 = cf2.get(7, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new RuntimeException(e);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
throw new RuntimeException(e);
}
System.out.println("get result2 : " + result2);
final String newRs1 = result1;
final String newRs2 = result2;
CompletableFuture.allOf(cf1, cf2).thenRun(() -> {
System.out.println("newRs1 + newRs2 : " + (newRs1 + newRs2));
System.out.println("任务都结束了");
});
}
}
运行结果如下:
任务1开始!
任务2结束!
任务1结束!
get result1 : 11
get result2 : 22
newRs1 + newRs2 : 1122
任务都结束了
将多个微服务调用放到CompletableFuture去执行,最终通过allOf方法将多个异步线程的执行结果串联起来,只不过每个线程返回的结果还需重定义为final类型,将每个异步执行的结果作为最终需要包装返回给客户端的入参。
补充
上面的示例是用到了JDK原生的工具类,实际开发过程中可以借助第三方工具类,比方说hutool的ThreadUtil工具类。第三方工具类无非也是基于CompletableFuture进行封装的。
本文参考了:博客园-乐之者