CompletableFuture 学习笔记
1.背景
最近在项目中存在多个调用外部接口的业务,如果串行调用耗时太多,通过使用CompletableFuture可以大大提高调用效率。
2.基本使用
2.1 个人看法
关于CompletableFuture查询资料以及自我的使用,使用基本分三个部分,创建异步任务,异步任务回调,多个任务组合处理。其中多个API基本上可以通过有无返回值,是否作为入参区分。而在异步任务回调中我之前想法是既然异步任务是等待上一个任务执行完后再继续执行thenRun()或者其他的什么回调任务,那么我直接串行执行不就可以了么为为什么还要回调函数这些呢,然后思考一会发现,使用CompletableFuture是当前任务的执行链和主线程的关系是异步的也就是说主线程还会继续执行下去(刚开始没反应过来QAQ)。虽然有很多API不过目前常用的就是创建异步任务后,通过allof整合起来,异步的执行任务然后通过join获取整合后的数据返回,目前我只使用了这一部分用来提升接口的响应速度,同时总结以便之后的学习使用。
2.2 创建异步任务
-
supplyAsync执行CompletableFuture任务,支持返回值
-
runAsync执行CompletableFuture任务,没有返回值。(往往执行一般是需要返回值的所以我一般不用这条)
@Test
public void testA() {
int a = 1;
int b = 2;
int c = CompletableFuture.supplyAsync(() -> {
return a + b;
}).join();
System.out.println(c);
}
2.3 任务异步回调
根据图片前六个每两个一组的区别,也就是Async后缀与没有该后缀,如果你执行第一个任务的时候,传入了一个自定义线程池:
调用XXX方法执行第二个任务时,则第二个任务和第一个任务是共用同一个线程池。
调用XXXAsync执行第二个任务时,则第一个任务使用的是你自己传入的线程池,第二个任务使用的是ForkJoin线程池。
然后每组有按照是否依赖上一个的结果作为参数,回调方法是否返回结果分为三组。
2.4 任务组合处理
多数api和上面的区别基本差不多,目前接受的项目优化过程中往往是使用allof汇总多个supplyAsync的任务当执行完成后通过一一join对应的结果然后汇总处理数据,从而降低接口调用外部接口串行带来的时间开销大致模板如下。(往往使用AtomicReference类创建实例便于多个线程的并发处理)
@Test
public void testB() {
AtomicReference<Integer> result = new AtomicReference<>(0);
CompletableFuture<Integer> methodA = CompletableFuture.supplyAsync(() -> {
System.out.println("调用方法A 返回1");
return 1;
});
CompletableFuture<Integer> methodB = CompletableFuture.supplyAsync(() -> {
System.out.println("调用方法B 返回2");
return 2;
});
CompletableFuture<Integer> methodC = CompletableFuture.supplyAsync(() -> {
System.out.println("调用方法C 返回3");
return 3;
});
CompletableFuture.allOf(methodA,methodB,methodC).thenRun(() ->{
Integer resultA = methodA.join();
Integer resultB = methodB.join();
Integer resultC = methodC.join();
result.set(resultA + resultC + resultB);
}).join();
System.out.println(result.get());
}
参考文章:https://blog.csdn.net/qq_38765404/article/details/120305045