前言
在Java并发编程中,CompletableFuture是一个强大而灵活的工具。今天,我们将深入探讨它的实现原理、最佳实践,以及面试中的重要考点。
一、CompletableFuture的本质
CompletableFuture是Java 8引入的异步编程工具,它实现了Future和CompletionStage两个接口。这个设计让它既保持了Future的基本特性,又通过CompletionStage接口提供了强大的任务编排能力。
让我们先看一个基本示例:
public class CompletableFutureBasics {
public static void main(String[] args) {
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
sleep(1000);
return "Hello";
}).thenApply(result -> {
// 转换结果
return result + " World";
});
// 非阻塞方式处理结果
future.thenAccept(System.out::println);
}
}
2、核心方法
2.1 实例方法
public class Completable01 {
public static void main(String[] args) throws Exception {
// 线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
// 1、创建未完成的CompletableFuture,通过complete()方法完成
CompletableFuture<Integer> cft01 = new CompletableFuture<>() ;
cft01.complete(99) ;
// 2、创建已经完成CompletableFuture,并且给定结果
CompletableFuture<String> cft02 = CompletableFuture.completedFuture("given...value");
// 3、有返回值,默认ForkJoinPool线程池
CompletableFuture<String> cft03 = CompletableFuture.supplyAsync(() -> {return "OK-3";});
// 4、有返回值,采用Executor自定义线程池
CompletableFuture<String> cft04 = CompletableFuture.supplyAsync(() -> {return "OK-4";},executor);
// 5、无返回值,默认ForkJoinPool线程池
CompletableFuture<Void> cft05 = CompletableFuture.runAsync(() -> {});
// 6、无返回值,采用Executor自定义线程池
CompletableFuture<Void> cft06 = CompletableFuture.runAsync(()-> {}, executor);
}
}
2.2 计算方法
public class Completable02 {
public static void main(String[] args) throws Exception {
// 线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft01 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK";
},executor);
// 1、计算完成后,执行后续处理
// cft01.whenComplete((res, ex) -> System.out.println("Result:"+res+";Exe:"+ex));
// 2、触发计算,如果没有完成,则get设定的值,如果已完成,则get任务返回值
// boolean completeFlag = cft01.complete("given...value");
// if (completeFlag){
// System.out.println(cft01.get());
// } else {
// System.out.println(cft01.get());
// }
// 3、开启新CompletionStage,重新获取线程执行任务
cft01.whenCompleteAsync((res, ex) -> System.out.println("Result:"+res+";Exe:"+ex),executor);
}
}
2.3 结果获取方法
public class Completable03 {
public static void main(String[] args) throws Exception {
// 线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft01 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "Res...OK";
},executor);
// 1、阻塞直到获取结果
// System.out.println(cft01.get());
// 2、设定超时的阻塞获取结果
// System.out.println(cft01.get(4, TimeUnit.SECONDS));
// 3、非阻塞获取结果,如果任务已经完成,则返回结果,如果任务未完成,返回给定的值
// System.out.println(cft01.getNow("given...value"));
// 4、get获取抛检查异常,join获取非检查异常
System.out.println(cft01.join());
}
}
2.4 任务编排方法
public class Completable04 {
public static void main(String[] args) throws Exception {
// 线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft01 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("OK-1");
return "OK";
},executor);
// 1、cft01任务执行完成后,执行之后的任务,此处不关注cft01的结果
// cft01.thenRun(() -> System.out.println("task...run")) ;
// 2、cft01任务执行完成后,执行之后的任务,可以获取cft01的结果
// cft01.thenAccept((res) -> {
// System.out.println("cft01:"+res);
// System.out.println("task...run");
// });
// 3、cft01任务执行完成后,执行之后的任务,获取cft01的结果,并且具有返回值
// CompletableFuture<Integer> cft02 = cft01.thenApply((res) -> {
// System.out.println("cft01:"+res);
// return 99 ;
// });
// System.out.println(cft02.get());
// 4、顺序执行cft01、cft02
// CompletableFuture<String> cft02 = cft01.thenCompose((res) -> CompletableFuture.supplyAsync(() -> {
// System.out.println("cft01:"+res);
// return "OK-2";
// }));
// cft02.whenComplete((res,ex) -> System.out.println("Result:"+res+";Exe:"+ex));
// 5、对比任务的执行效率,由于cft02先完成,所以取cft02的结果
// CompletableFuture<String> cft02 = cft01.applyToEither(CompletableFuture.supplyAsync(() -> {
// System.out.println("run...cft02");
// try {
// Thread.sleep(3000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// return "OK-2";
// }),(res) -> {
// System.out.println("either...result:" + res);
// return res;
// });
// System.out.println("finally...result:" + cft02.get());
// 6、两组任务执行完成后,对结果进行合并
// CompletableFuture<String> cft02 = CompletableFuture.supplyAsync(() -> "OK-2") ;
// String finallyRes = cft01.thenCombine(cft02,(res1,res2) -> {
// System.out.println("res1:"+res1+";res2:"+res2);
// return res1+";"+res2 ;
// }).get();
// System.out.println(finallyRes);
CompletableFuture<String> cft02 = CompletableFuture.supplyAsync(() -> {
System.out.println("OK-2");
return "OK-2";
}) ;
CompletableFuture<String> cft03 = CompletableFuture.supplyAsync(() -> {
System.out.println("OK-3");
return "OK-3";
}) ;
// 7、等待批量任务执行完返回
// CompletableFuture.allOf(cft01,cft02,cft03).get();
// 8、任意一个任务执行完即返回
System.out.println("Sign:"+CompletableFuture.anyOf(cft01,cft02,cft03).get());
}
}
2.5 异常处理方法
public class Completable05 {
public static void main(String[] args) throws Exception {
// 线程池
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft01 = CompletableFuture.supplyAsync(() -> {
if (1 > 0){
throw new RuntimeException("task...exception");
}
return "OK";
},executor);
// 1、捕获cft01的异常信息,并提供返回值
String finallyRes = cft01.thenApply((res) -> {
System.out.println("cft01-res:" + res);
return res;
}).exceptionally((ex) -> {
System.out.println("cft01-exe:" + ex.getMessage());
return "error" ;
}).get();
System.out.println("finallyRes="+finallyRes);
CompletableFuture<String> cft02 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK-2";
},executor);
// 2、如果cft02未完成,则get时抛出指定异常信息
boolean exeFlag = cft02.completeExceptionally(new RuntimeException("given...exception"));
if (exeFlag){
System.out.println(cft02.get());
} else {
System.out.println(cft02.get());
}
}
}
3、线程池问题
- 在实践中,通常不使用ForkJoinPool#commonPool()公共线程池,会出现线程竞争问题,从而形成系统瓶颈;
- 在任务编排中,如果出现依赖情况或者父子任务,尽量使用多个线程池,从而避免任务请求同一个线程池,规避死锁情况发生;
二、核心原理解析
2.1、核心数据结构
- CompletableFuture内部实现了一个精巧的状态机:
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
// 存储计算结果或异常
volatile Object result;
// 存储依赖任务的栈
volatile Completion stack;
// 用于控制并发操作的CAS标志位
volatile int status;
}
2.1.1、状态字段(status)
状态字段使用位运算来表示多个状态:
// 内部状态常量
private static final int SYNC = 1; // 同步完成态
private static final int ASYNC = 2; // 异步完成态
private static final int REL = 4; // 等待释放
private static final int THROWN = 8; // 异常完成
private static final int INTERRUPTED = 16; // 中断状态
这些状态通过位运算组合使用,例如:
// 判断是否完成的代码片段
final boolean isDone() {
return (status & (SYNC | ASYNC)) != 0;
}
2.2、完成机制
CompletableFuture 的完成机制是通过 CAS (Compare-And-Swap) 操作实现的:
// 简化的完成操作代码
boolean completeValue(T t) {
return UNSAFE.compareAndSwapObject(this, RESULT, null, t) &&
UNSAFE.compareAndSwapInt(this, STATUS, 0, SYNC);
}
这里展示了完成操作的原子性保证:
- 首先尝试设置结果值
- 然后更新状态为完成态
- 如果任何一步失败,说明其他线程已经完成了操作
2.3、依赖关系管理
CompletableFuture 使用 Completion 类来管理任务之间的依赖关系:
abstract class Completion extends ForkJoinTask<Void> implements Runnable {
volatile Completion next; // 下一个依赖任务
volatile CompletableFuture<?> src; // 源Future
volatile CompletableFuture<?> dep; // 依赖Future
}
- 当我们使用 thenApply、thenAccept 等方法时,实际上是创建了新的 Completion 对象:
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {
return uniComposeStage(null, fn);
}
// 简化的实现原理
private <U> CompletableFuture<U> uniComposeStage(Executor e, Function<? super T,? extends U> fn) {
CompletableFuture<U> dst = new CompletableFuture<U>();
// 创建新的Completion并加入依赖链
UniCompletion<T,U> c = new UniCompletion<>(e, dst, this, fn);
push(c);
return dst;
}
这种设计允许任务之间形成一个有向无环图(DAG),支持复杂的任务编排。
2.4、执行机制
CompletableFuture 的执行依赖于 ForkJoinPool,但也支持自定义线程池:
// 内部执行器选择逻辑
private Executor defaultExecutor() {
return ASYNC_POOL; // 默认使用ForkJoinPool.commonPool()
}
// 异步执行示例
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(ASYNC_POOL, supplier);
}
2.5、触发机制
当一个 CompletableFuture 完成时,会触发其依赖任务的执行:
// 简化的触发逻辑
final void postComplete() {
// 1. 获取当前的依赖栈
CompletableFuture<?> f = this;
Completion h = f.stack;
// 2. 遍历并触发所有依赖任务
while (h != null) {
Completion t = h.next;
h.next = null;
f = h.tryFire(NESTED);
h = t;
}
}
2.6、性能优化
CompletableFuture 包含多项性能优化:
- 1、栈压缩:
// 压缩依赖栈,减少内存占用
final void cleanStack() {
Completion p = stack;
// 删除已完成的依赖
while (p != null) {
Completion next = p.next;
if (p.isLive()) break;
UNSAFE.compareAndSwapObject(this, STACK, p, next);
p = next;
}
}
- 2、快速路径优化:
// 对于已完成的Future,直接执行转换操作
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {
if (result != null) // 已完成,直接执行转换
return completedFuture(fn.apply(result));
return uniComposeStage(null, fn); // 未完成,创建新的依赖
}
2.7、工作流程示例
让我们通过一个完整的示例来理解整个工作流程:
CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture<String> future2 = future1.thenApply(s -> s + " World");
// 内部发生的事情:
// 1. supplyAsync创建第一个CompletableFuture,并将任务提交到ForkJoinPool
// 2. thenApply创建第二个CompletableFuture,并创建Completion对象
// 3. Completion对象被添加到future1的依赖栈中
// 4. 当future1完成时,触发postComplete,执行依赖任务
// 5. 依赖任务执行完成后,future2被标记为完成状态
2.8、内存模型保证
CompletableFuture 通过 volatile 变量和 CAS 操作保证了内存可见性和操作原子性:
class CompletableFuture<T> {
volatile Object result; // 保证结果的可见性
// CAS操作保证原子性
boolean casResult(Object cmp, Object val) {
return UNSAFE.compareAndSwapObject(this, RESULT, cmp, val);
}
}
通过这些底层机制的配合,CompletableFuture 实现了:
- 高效的异步任务执行
- 灵活的任务组合
- 可靠的异常处理
- 良好的性能表现
2.9 Completion 抽象类
Completion 抽象类用于表示一个完成操作,它可能会在任务完成时被触发,并且它们在链表中以 Treiber stack 形式存储。
abstract static class Completion extends ForkJoinTask<Void>
implements Runnable, AsynchronousCompletionTask {
// `next` 属性指向链表中的下一个 `Completion` 对象
volatile Completion next;
/**
* 在任务完成时执行完成操作,如果需要的话,返回可能需要传播的依赖。
*
* @param mode 完成模式,可以是 SYNC、ASYNC 或 NESTED
* @return 如果存在依赖需要传播,则返回它
*/
abstract CompletableFuture<?> tryFire(int mode);
/**
* 返回 true 如果当前 `Completion` 对象可能仍然可以被触发。
* 用于 `cleanStack` 方法来检查当前 `Completion` 是否仍然有效。
*
* @return 如果 `Completion` 可能仍然可以触发,则返回 true
*/
abstract boolean isLive();
// 实现 `Runnable` 接口的 `run` 方法,调用 `tryFire` 方法,模式为 ASYNC
public final void run() {
tryFire(ASYNC);
}
// 实现 `ForkJoinTask` 的 `exec` 方法,调用 `tryFire` 方法,模式为 ASYNC
public final boolean exec() {
tryFire(ASYNC);
return true;
}
// 实现 `ForkJoinTask` 的方法,`getRawResult` 返回 null
public final Void getRawResult() {
return null;
}
// 实现 `ForkJoinTask` 的方法,`setRawResult` 不执行任何操作
public final void setRawResult(Void v) {}
}
Completion 的子类:
任务链式调用:
以下面这段伪代码举例:
CompletableFuture.supplyAsync(() -> {task1}).thenApply(()->{task2}).thenRun(()->{task3});
- 上面通过supplyAsync、thenApply、thenRun方法,分别提交了3个任务,每个方法都会返回一个CompletableFuture对象。
- 其中task2会被放入task1的CompletableFuture 维护的Completion stack也就是Treiber栈中。当task1完成时,会从自己的Treiber栈中
弹出下一个任务task2执行。- 如此传递下去、task3会被放入task2的CompletableFuture 维护的Completion stack也就是Treiber栈中。当task2完成时,会从自己的Treiber栈中弹出下一个任务task3执行。
总结下任务的链式调用机制:
栈结构: 每个 CompletableFuture 维护了一个 Completion 链表,链表中存储了所有需要在当前 CompletableFuture 完成时执行的任务。当一个任务(如task1)完成时,它会遍历链表中的 Completion 对象,将任务按顺序执行。
任务触发: run方法会调用tryFire 方法来触发链表中的任务,这样每个任务都能按照预定顺序执行。
其实对于任务的链式调用完全可以不使用栈结构,直接用一个指针把所有任务串成一个单向链表结构就可以了。
但实际上任务还有许多复杂的组合方式,要支持这些任务的各种组合,就需要使用栈结构了。
2.10 Completion依赖
在CompletableFuture类中有两个关键的字段:「result」存储当前CF的结果,「stack」代表栈顶元素,即当前CF计算完成后会触发的依赖动作;从上面案例中可知,依赖动作可以没有或者有多个;
Completion:依赖动作的封装类;
UniCompletion:继承Completion类,一元依赖的基础类,「executor」指线程池,「dep」指依赖的计算,「src」指源动作;
BiCompletion:继承UniCompletion类,二元或者多元依赖的基础类,「snd」指第二个源动作;
2.10.1 零依赖
顾名思义,即各个CF之间不产生依赖关系;
public class DepZero {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft1 = CompletableFuture.supplyAsync(()-> "OK-1",executor);
CompletableFuture<String> cft2 = CompletableFuture.supplyAsync(()-> "OK-2",executor);
System.out.println(cft1.get()+";"+cft2.get());
}
}
2.10.2 一元依赖
即CF之间的单个依赖关系;这里使用「thenApply」方法演示,为了看到效果,使「cft1」长时间休眠,断点查看「stack」结构;
public class DepOne {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK-1";
},executor);
CompletableFuture<String> cft2 = cft1.thenApply(res -> {
System.out.println("cft01-res"+res);
return "OK-2" ;
});
System.out.println("cft02-res"+cft2.get());
}
}
-
断点截图
image.png
-
原理分析
image.png
观察者Completion注册到「cft1」,注册时会检查计算是否完成,未完成则观察者入栈,当「cft1」计算完成会弹栈;已完成则直接触发观察者;
可以调整断点代码,让「cft1」先处于完成状态,再查看其运行时结构,从而分析完整的逻辑;
2.10.3 二元依赖
即一个CF同时依赖两个CF;这里使用「thenCombine」方法演示;为了看到效果,使「cft1、cft2」长时间休眠,断点查看「stack」结构;
public class DepTwo {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK-1";
},executor);
CompletableFuture<String> cft2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK-2";
},executor);
// cft3 依赖 cft1和cft2 的计算结果
CompletableFuture<String> cft3 = cft1.thenCombine(cft2,(res1,res2) -> {
System.out.println("cft01-res:"+res1);
System.out.println("cft02-res:"+res2);
return "OK-3" ;
});
System.out.println("cft03-res:"+cft3.get());
}
}
-
断点截图
image.png
-
原理分析
image.png
在「cft1」和「cft2」未完成的状态下,尝试将BiApply压入「cft1」和「cft2」两个栈中,任意CF完成时,会尝试触发观察者,观察者检查「cft1」和「cft2」是否都完成,如果完成则执行;
2.10.4 多元依赖
即一个CF同时依赖多个CF;这里使用「allOf」方法演示;为了看到效果,使「cft1、cft2、cft3」长时间休眠,断点查看「stack」结构;
public class DepMore {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(3);
CompletableFuture<String> cft1 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK-1";
},executor);
CompletableFuture<String> cft2 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK-2";
},executor);
CompletableFuture<String> cft3 = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(30000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "OK-3";
},executor);
// cft4 依赖 cft1和cft2和cft3 的计算结果
CompletableFuture<Void> cft4 = CompletableFuture.allOf(cft1,cft2,cft3);
CompletableFuture<String> finallyRes = cft4.thenApply(tm -> {
System.out.println("cft01-res:"+cft1.join());
System.out.println("cft02-res:"+cft2.join());
System.out.println("cft03-res:"+cft3.join());
return "OK-4";
});
System.out.println("finally-res:"+finallyRes.get());
}
}
-
断点截图
image.png
-
原理分析
image.png
多元依赖的回调方法除了「allOf」还有「anyOf」,其实现原理都是将依赖的多个CF补全为平衡二叉树,从断点图可知会按照树的层级处理,核心结构参考二元依赖即可;
三、实践应用
1. 并行任务处理
在微服务架构中,CompletableFuture常用于优化调用链路:
public class ServiceCaller {
public OrderDetails getOrderDetails(Long orderId) {
CompletableFuture<UserInfo> userInfo = getUserAsync(orderId);
CompletableFuture<OrderInfo> orderInfo = getOrderAsync(orderId);
CompletableFuture<PaymentInfo> paymentInfo = getPaymentAsync(orderId);
return CompletableFuture.allOf(userInfo, orderInfo, paymentInfo)
.thenApply(v -> combineResults(
userInfo.join(),
orderInfo.join(),
paymentInfo.join()
))
.completeOnTimeout(
OrderDetails.getDefault(),
3,
TimeUnit.SECONDS
)
.join();
}
}
2. 异常处理最佳实践
合理的异常处理对于生产环境至关重要:
public class ExceptionHandlingExample {
public CompletableFuture<Result> robustOperation() {
return CompletableFuture.supplyAsync(this::riskyOperation)
.handle((result, throwable) -> {
if (throwable != null) {
log.error("操作失败", throwable);
return Result.failure(throwable);
}
return Result.success(result);
})
.whenComplete((result, throwable) -> {
metrics.record(result.isSuccess());
});
}
}
3. 性能优化实践
实际应用中的性能优化策略:
public class PerformanceOptimization {
// 批量处理优化
public List<Result> batchProcess(List<Task> tasks) {
return Lists.partition(tasks, 100)
.stream()
.map(batch -> {
List<CompletableFuture<Result>> futures = batch.stream()
.map(this::processAsync)
.collect(Collectors.toList());
return CompletableFuture.allOf(
futures.toArray(new CompletableFuture[0])
)
.thenApply(v -> futures.stream()
.map(CompletableFuture::join)
.collect(Collectors.toList())
)
.join();
})
.flatMap(List::stream)
.collect(Collectors.toList());
}
}
四、高频面试题解析
CompletableFuture与Future的区别?
-
异步回调能力
- Future:不支持回调函数,完成后需要通过 get() 方法阻塞扽得改。
- CompletableFuture:允许通过 then 系列方法注册回调函数,计算完成后可以立即执行。
-
任务组合能力
- Future:不支持任务组合。
- CompletableFuture:提供了丰富的操作方法,允许使用 then、thenAccept、thenCombine、allof 等方法来组合和串联多个异步任务,构建复杂的流程。使得代码更加清晰以及便于维护。
-
异常处理机制
- Future:使用 get() 方法获取结果时,如果计算出错,会抛出一个检查异常(ExecutionException)。处理异常比较繁琐。
- CompletableFuture:提供了 exceptionally 和 handle 方法来处理异常,使得异常处理更加灵活、优雅。
-
手动完成能力
- Future:Future接口定义了一个异步计算的结果,但它不支持手动完成任务。Future对象只能等待任务自然完成,无法主动控制任务的完成状态。如果任务未完成,调用get()方法会阻塞当前线程,直到任务完成。
- CompletableFuture:CompletableFuture扩展了Future的功能,提供了complete方法,可以主动完成任务。这意味着开发者可以在适当的时机手动设置任务的结果,而不需要等待任务自然完成。此外,CompletableFuture还提供了completeExceptionally方法,用于处理任务执行过程中发生的异常。
-
链式调用
- Future:不支持链式调用。
- CompletableFuture:提供了丰富的链式调用方法,如thenApply、thenCompose等,可以方便地将多个异步操作组合在一起处理。操作链中的任务是非阻塞的,可以提高并发性能。
CompletableFuture的线程池机制?
- 默认使用ForkJoinPool.commonPool()
- 支持自定义线程池
- 线程池参数配置建议
- 异步方法的线程选择策略
如何处理CompletableFuture的异常?
- exceptionally:异常恢复
- handle:结果和异常处理
- whenComplete:后置处理
- 异常传播机制
CompletableFuture的性能优化方式?
- 线程池优化
- 批量处理策略
- 超时控制
- 资源管理
实际项目中的应用案例?
- 微服务调用链路优化
- 并行数据处理
- 异步任务编排
- 服务降级策略
五、总结
CompletableFuture是Java并发编程中的重要工具,它通过巧妙的设计提供了强大的异步编程能力。要充分发挥它的优势,需要:
- 深入理解其实现原理
- 掌握正确的使用方式
- 注意性能优化
- 实践异常处理
- 合理进行任务编排
参考:
https://blog.csdn.net/daweias/article/details/144135198
https://blog.csdn.net/qq_37883866/article/details/140908231