📖目录
- 引言:为什么我们需要CompletableFuture?
- [1. 前传:Future 与 CompletableFuture 的爱恨情仇](#1. 前传:Future 与 CompletableFuture 的爱恨情仇)
-
- [1.1 Future:异步编程的"半成品"](#1.1 Future:异步编程的“半成品”)
- [1.2 CompletableFuture:Future 的"完全体"](#1.2 CompletableFuture:Future 的“完全体”)
- [2. 大白话解释:CompletableFuture如何工作?](#2. 大白话解释:CompletableFuture如何工作?)
- [3. 源码深潜:CompletableFuture 的内部引擎](#3. 源码深潜:CompletableFuture 的内部引擎)
-
- [3.1 核心数据结构:Completion 链表](#3.1 核心数据结构:Completion 链表)
- [3.2 join() 的奥秘:UNSAFE 与 LockSupport](#3.2 join() 的奥秘:UNSAFE 与 LockSupport)
- [4. 多个CompletableFuture的组合艺术:allOf vs anyOf](#4. 多个CompletableFuture的组合艺术:allOf vs anyOf)
-
- [4.1 allOf:团队协作,一个都不能少](#4.1 allOf:团队协作,一个都不能少)
- [4.2 anyOf:竞速模式,先到先得](#4.2 anyOf:竞速模式,先到先得)
- [5. 异常处理的高级技巧:优雅地面对"翻车"](#5. 异常处理的高级技巧:优雅地面对“翻车”)
-
- [5.1 exceptionally:专属的"急救包"](#5.1 exceptionally:专属的“急救包”)
- [5.2 handle:无论成败,都要有个交代](#5.2 handle:无论成败,都要有个交代)
- [6. 与虚拟线程(Virtual Threads)的完美结合](#6. 与虚拟线程(Virtual Threads)的完美结合)
-
- [6.1 虚拟线程:轻量级的"协程"](#6.1 虚拟线程:轻量级的“协程”)
- [6.2 CompletableFuture + 虚拟线程 = 高并发新范式](#6.2 CompletableFuture + 虚拟线程 = 高并发新范式)
- [7. CompletableFuture vs Reactive Streams:两种异步哲学](#7. CompletableFuture vs Reactive Streams:两种异步哲学)
- [8. 实战示例:微服务间的异步调用](#8. 实战示例:微服务间的异步调用)
-
- [8.1 示例1:使用allOf聚合多个微服务响应](#8.1 示例1:使用allOf聚合多个微服务响应)
- [8.2 示例2:使用anyOf实现服务降级](#8.2 示例2:使用anyOf实现服务降级)
- [8.3 示例3:结合虚拟线程处理海量请求](#8.3 示例3:结合虚拟线程处理海量请求)
- [8.4 示例4:完整的异常处理链](#8.4 示例4:完整的异常处理链)
- [9. 结语:CompletableFuture不是银弹,但它是异步编程的利器](#9. 结语:CompletableFuture不是银弹,但它是异步编程的利器)
- [10. 经典书籍推荐](#10. 经典书籍推荐)
- [11. 下一篇预告](#11. 下一篇预告)
- [12. 往期博客回顾](#12. 往期博客回顾)
引言:为什么我们需要CompletableFuture?
想象一下,你正在筹备一场大型婚礼。你需要同时协调多个供应商:摄影师、化妆师、酒店、婚庆公司。如果采用传统的同步方式,你会这样操作:
- 先打电话给摄影师,等他确认档期。
- 然后打电话给化妆师,等她确认档期。
- 接着联系酒店...
整个过程是串行的,效率极低。万一某个环节出问题(比如酒店临时涨价),你可能会手忙脚乱。
在软件世界里,我们经常面临类似场景:需要同时调用多个外部服务(如用户服务、订单服务、库存服务),并等待它们的结果。CompletableFuture 就是为了解决这种复杂异步协作而生的。它让你可以像指挥家一样,优雅地编排多个异步任务,无论是等待所有任务完成(allOf),还是只关心最快的那个结果(anyOf),甚至是处理各种意外情况(异常处理)。
更重要的是,在 Java 21 引入了虚拟线程(Virtual Threads)之后,CompletableFuture 的威力被进一步放大,为我们构建超高并发、低延迟的应用提供了全新的可能性。
1. 前传:Future 与 CompletableFuture 的爱恨情仇
在深入 CompletableFuture 之前,我们必须理解它的前辈------Future。它们之间的关系,就像是从"能跑的马车"进化到了"带自动驾驶的智能汽车"。
1.1 Future:异步编程的"半成品"
java.util.concurrent.Future 是 Java 5 引入的接口,代表一个异步计算的结果。它的核心思想是:"我现在去办事,给你一张凭证(Future),你稍后再凭这张凭证来取结果。"
java
// Future 的典型用法
ExecutorService executor = Executors.newFixedThreadPool(2);
Future<String> future = executor.submit(() -> {
// 模拟耗时任务
Thread.sleep(1000);
return "Hello, Future!";
});
// 主线程可以去做别的事...
// ...
// 在需要结果时,阻塞等待
String result = future.get(); // 这里会阻塞!
Future 的三大痛点:
- 被动等待 :你无法主动为
Future注册回调。唯一获取结果的方式就是调用get(),这会导致当前线程阻塞,失去了异步的意义。 - 无法组合 :如果有两个
Future,你想等它们都完成后再做点事?抱歉,Future本身不提供任何组合方法,你只能手动轮询或阻塞。 - 异常处理笨拙 :
get()方法会抛出ExecutionException,你需要手动解包才能拿到真正的业务异常。
简而言之,Future 只解决了"异步执行"的问题,但没有解决"异步协作"和"非阻塞处理结果"的问题。
1.2 CompletableFuture:Future 的"完全体"
CompletableFuture 在 Java 8 中诞生,它实现了 Future 接口 ,因此它首先是一个 Future。但它更是一个强大的构建块(Building Block) ,因为它引入了函数式编程 和声明式组合的能力。
| 特性 | Future |
CompletableFuture |
|---|---|---|
| 是否实现 Future | 是 | 是 |
| 主动回调 | ❌ 不支持 | ✅ 支持 (thenApply, thenAccept 等) |
| 任务组合 | ❌ 不支持 | ✅ 支持 (allOf, anyOf, thenCombine 筇) |
| 异常处理 | ❌ 笨拙 (get() 抛异常) |
✅ 优雅 (exceptionally, handle) |
| 手动完成 | ❌ 不可能 | ✅ 可以 (complete(), completeExceptionally()) |
CompletableFuture 不仅继承了 Future 的衣钵,更通过一系列流畅的 API,让我们能够以非阻塞、声明式的方式,将多个异步任务编织成一张复杂的协作网络。这才是现代异步编程应有的样子。
2. 大白话解释:CompletableFuture如何工作?
可以把 CompletableFuture 想象成一个"智能快递单"。
- 下单(创建Future) :当你发起一个异步任务(比如
supplyAsync),就像下了一个快递单。此时你手上只有一个单号(CompletableFuture对象),包裹(结果)还在路上。 - 追踪与处理(回调) :你可以在这个单号上注册一系列操作,比如"包裹到了通知我"(
thenAccept)、"包裹到了帮我拆开并把里面的东西转寄给另一个人"(thenApply)。这些操作会形成一个链条。 - 最终交付(获取结果) :当所有前置任务都完成后,你最终可以通过
join()或get()拿到包裹(结果),或者通过回调自动处理它。
这种"声明式"的编程方式,让你的代码逻辑清晰,避免了传统回调地狱(Callback Hell)的混乱。
3. 源码深潜:CompletableFuture 的内部引擎
CompletableFuture 的魔力并非凭空而来,其内部精巧的设计是性能和功能的基石。我们来揭开它的面纱。
3.1 核心数据结构:Completion 链表
CompletableFuture 的核心在于一个名为 Completion 的内部抽象类。每一个你在 CompletableFuture 上注册的回调(如 thenApply, thenAccept),都会被封装成一个 Completion 的子类实例(例如 UniApply, UniAccept)。
这些 Completion 实例会以栈 (Stack)的形式(通过 next 指针链接)挂载在对应的 CompletableFuture 对象上。
流程图:CompletableFuture 回调链
stack
next
next
当 cf 完成时
cf.result = value
for c in stack: c.tryFire
C1.tryFire
C2.tryFire
C3.tryFire
CompletableFuture cf
Completion C3
Completion C2
Completion C1
执行流程:
- 当
CompletableFuture的任务完成(通过complete(value)或obtrudeValue(value))时,它会将结果存入内部的result字段。 - 紧接着,它会遍历自己身上挂载的
Completion栈。 - 对每个
Completion调用tryFire(mode)方法。这个方法会检查其依赖的CompletableFuture是否已完成,如果已完成,就执行具体的回调逻辑(如apply函数),并将结果传递给下一个CompletableFuture。 - 这个过程会像多米诺骨牌一样,沿着回调链一路触发下去,直到所有依赖的任务都完成。
这种设计使得任务的触发是惰性 (Lazy)且高效 的,只有在源头 Future 完成后,后续的计算才会被激活。
3.2 join() 的奥秘:UNSAFE 与 LockSupport
当我们调用 cf.join() 时,如果 cf 还未完成,当前线程会阻塞。那么,JVM 是如何知道何时唤醒这个线程的呢?
答案就在 join() 方法的底层实现中,它最终会调用到 awaitDone(boolean timed, long nanos) 方法。其核心逻辑如下:
- 自旋检查 :首先在一个循环中快速检查
result字段是否已经设置(使用UNSAFE.getObjectVolatile保证可见性)。这是为了应对任务恰好在调用join()后瞬间完成的情况,避免不必要的线程挂起开销。 - 线程挂起 :如果自旋几次后任务仍未完成,当前线程会被封装成一个
WaitNode,并加入到CompletableFuture的waiters链表中。 - 调用 LockSupport.park() :然后,线程会调用
LockSupport.park()进入WAITING状态,释放CPU。 - 唤醒机制 :当
CompletableFuture最终完成时,在遍历Completion链的同时,也会遍历waiters链表,并对其中的每个WaitNode调用LockSupport.unpark(thread)。 - 线程恢复 :被
unpark的线程会从park()处恢复执行,再次检查result,此时必然已有值,于是返回结果。
这个过程巧妙地结合了自旋 (减少上下文切换)和阻塞(避免CPU空转),是Java并发库中非常经典的等待/通知模式。
4. 多个CompletableFuture的组合艺术:allOf vs anyOf
CompletableFuture 最强大的地方在于它能轻松组合多个异步任务。
4.1 allOf:团队协作,一个都不能少
CompletableFuture.allOf(...) 就像一个项目负责人,必须等到所有团队成员(子任务)都提交了报告,他才能汇总并向老板汇报。
| 特性 | allOf |
生活比喻 |
|---|---|---|
| 触发条件 | 所有传入的 CompletableFuture 都完成 |
婚礼所有供应商都确认到位 |
| 返回值 | CompletableFuture<Void>,本身不携带结果,但可以用来触发后续动作 |
一个"万事俱备"的信号 |
| 异常处理 | 任何一个子任务失败,allOf 也会立即失败 |
任何一个供应商掉链子,整个婚礼计划就泡汤 |
4.2 anyOf:竞速模式,先到先得
CompletableFuture.anyOf(...) 则像是一个竞标系统,只要有任何一个投标方(子任务)给出了报价,就可以立刻成交。
| 特性 | anyOf |
生活比喻 |
|---|---|---|
| 触发条件 | 任意一个传入的 CompletableFuture 完成 |
多个快递公司抢单,谁先送到算谁的 |
| 返回值 | CompletableFuture<Object>,其结果是第一个完成的任务的结果 |
第一个送达的包裹 |
| 异常处理 | 如果第一个完成的任务是成功的,anyOf 就成功;如果第一个完成的是异常,则 anyOf 也失败 |
第一个快递员如果顺利送达,交易成功;如果他半路出了事故(异常),交易也算失败 |
5. 异常处理的高级技巧:优雅地面对"翻车"
现实世界充满了不确定性,网络超时、服务宕机都是家常便饭。CompletableFuture 提供了强大的异常处理机制。
5.1 exceptionally:专属的"急救包"
exceptionally 允许你为一个特定的 CompletableFuture 注册一个"急救方案"。如果这个任务失败了,就执行这个方案,并用它的返回值作为最终结果,从而让整个流程继续下去。
java
// 示例:如果获取用户信息失败,返回一个默认的匿名用户
CompletableFuture<User> future = getUserAsync(userId)
.exceptionally(ex -> {
System.err.println("获取用户失败: " + ex.getMessage());
return new User("anonymous");
});
5.2 handle:无论成败,都要有个交代
handle 是一个更通用的方法。它接收两个参数:正常结果(可能为null)和异常(可能为null)。你可以在一个方法里统一处理成功和失败两种情况。
java
// 示例:记录日志,无论成功与否
CompletableFuture<String> result = fetchData()
.handle((data, ex) -> {
if (ex != null) {
log.error("数据获取失败", ex);
return "DEFAULT_DATA";
} else {
log.info("数据获取成功");
return data;
}
});
6. 与虚拟线程(Virtual Threads)的完美结合
Java 21 引入的虚拟线程(Project Loom)是革命性的。传统平台线程(Platform Threads)很重,创建成千上万个成本高昂。而虚拟线程非常轻量,由 JVM 管理,可以轻松创建数百万个。
6.1 虚拟线程:轻量级的"协程"
可以把平台线程想象成"正式员工",每个都需要独立的办公桌(操作系统资源)。而虚拟线程则是"实习生",他们共享办公桌,由一个"经理"(载体平台线程)来调度。当一个实习生在等待(比如I/O操作)时,经理可以立刻切换到另一个实习生,极大地提高了资源利用率。
6.2 CompletableFuture + 虚拟线程 = 高并发新范式
过去,我们使用 CompletableFuture.supplyAsync(...) 时,通常会传入一个线程池(如 ForkJoinPool.commonPool())。在线程池大小有限的情况下,大量阻塞的 I/O 操作会很快耗尽线程,导致系统无法处理新请求。
现在,我们可以直接在虚拟线程中执行阻塞操作!因为虚拟线程的成本极低,即使有成千上万个虚拟线程在等待 I/O,JVM 也能高效地管理它们。
这意味着,对于 I/O 密集型任务,我们甚至可以简化代码,直接使用 CompletableFuture 的链式调用,而无需过度担心线程池的配置,因为底层的虚拟线程已经为我们解决了并发瓶颈。
7. CompletableFuture vs Reactive Streams:两种异步哲学
CompletableFuture 和 Reactive Streams(如 Project Reactor 的 Mono/Flux)都是处理异步流的强大工具,但它们的设计哲学不同。
| 特性 | CompletableFuture |
Reactive Streams |
|---|---|---|
| 核心思想 | Future/Promise 模型:代表一个未来会完成的单一值。 | 发布-订阅模型:代表一个可能包含0到N个元素的数据流。 |
| 背压(Backpressure) | 不支持。生产者和消费者之间没有速率协商机制。 | 核心特性。消费者可以控制生产者的发送速率,防止被淹没。 |
| 适用场景 | RPC调用、数据库查询等返回单一结果的场景。 | 事件流处理、实时数据管道等处理连续数据流的场景。 |
| 学习曲线 | 相对平缓,概念直观。 | 较陡峭,需要理解背压、操作符等概念。 |
| 与虚拟线程 | 天然契合。虚拟线程解决了其I/O阻塞的痛点。 | 已有自己的非阻塞I/O模型,虚拟线程对其影响较小。 |
简单来说,如果你的任务是"问一个问题,等一个答案",CompletableFuture 是绝佳选择。如果你的任务是"监听一条消息河,对每条消息做处理",那么 Reactive Streams 更合适。
8. 实战示例:微服务间的异步调用
下面我们将通过四个完整的示例,展示 CompletableFuture 在微服务场景下的强大能力。
8.1 示例1:使用allOf聚合多个微服务响应
场景:在一个电商应用中,渲染商品详情页需要同时获取商品信息、用户评论和推荐商品。这三个服务调用可以并行进行。
java
// 【插入 Example1_AllOf.java】
import java.util.concurrent.CompletableFuture;
public class Example1_AllOf {
// 模拟微服务调用
private static CompletableFuture<String> fetchProductInfo() {
return CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(1000); } catch (InterruptedException e) { }
return "Product Info: iPhone 15";
});
}
private static CompletableFuture<String> fetchReviews() {
return CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(1200); } catch (InterruptedException e) { }
return "Reviews: [Great phone!]";
});
}
private static CompletableFuture<String> fetchRecommendations() {
return CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(800); } catch (InterruptedException e) { }
return "Recommendations: [AirPods, Case]";
});
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
CompletableFuture<String> productFuture = fetchProductInfo();
CompletableFuture<String> reviewsFuture = fetchReviews();
CompletableFuture<String> recommendationsFuture = fetchRecommendations();
// 等待所有服务调用完成
CompletableFuture<Void> allDone = CompletableFuture.allOf(
productFuture, reviewsFuture, recommendationsFuture
);
// 当所有任务完成后,组装最终页面
allDone.thenRun(() -> {
String page = String.format(
"=== Product Detail Page ===\n%s\n%s\n%s",
productFuture.join(),
reviewsFuture.join(),
recommendationsFuture.join()
);
System.out.println(page);
System.out.println("Total time: " + (System.currentTimeMillis() - start) + "ms");
}).join(); // 主线程等待
}
}
执行结果预留位:
=== Product Detail Page ===
Product Info: iPhone 15
Reviews: [Great phone!]
Recommendations: [AirPods, Case]
Total time: 1274ms
8.2 示例2:使用anyOf实现服务降级
场景:为了提高系统的可用性,我们可以为关键服务部署主备实例。当主服务响应慢或失败时,可以快速切换到备用服务。
java
// 【插入 Example2_AnyOf.java】
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class Example2_AnyOf {
// 模拟一个可能很慢或失败的主服务
private static CompletableFuture<String> callPrimaryService() {
return CompletableFuture.supplyAsync(() -> {
try {
// 模拟网络延迟或故障:50%概率超时(3秒),50%概率抛异常
if (Math.random() > 0.5) {
Thread.sleep(3000); // 主服务超时场景
} else {
throw new RuntimeException("Primary service down! 主服务故障");
}
} catch (InterruptedException e) {
// 修复:不再空吞异常,打印日志+包装成运行时异常抛出
System.err.println("主服务请求被中断:" + e.getMessage());
throw new RuntimeException("Primary service interrupted!", e);
}
return "Primary Result 【主服务正常结果】";
})
// 主服务抛异常时,返回一个异常占位值,而不是让Future进入失败状态
.exceptionally(ex -> {
System.err.println("主服务调用失败:" + ex.getMessage());
return null; // 异常时返回null,标记主服务不可用
});
}
// 模拟一个稳定但数据可能稍旧的备用服务
private static CompletableFuture<String> callBackupService() {
return CompletableFuture.supplyAsync(() -> {
try { Thread.sleep(500); } catch (InterruptedException e) {
System.err.println("备用服务请求被中断:" + e.getMessage());
}
return "Backup Result (slightly stale) 【备用服务兜底结果】";
});
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
CompletableFuture<Object> fastResult = CompletableFuture.anyOf(
callPrimaryService(),
callBackupService()
);
try {
String result = (String) fastResult.join();
// 过滤主服务异常返回的null值
if (result == null) {
result = callBackupService().join(); // 兜底:主动调用备用服务
}
System.out.println("\n✅ Final result: " + result);
} catch (Exception e) {
// 极端情况:所有服务都失败,最终兜底提示
System.out.println("\n⚠️ All services failed! Use default result");
} finally {
// 必输耗时,无论成功失败都统计
System.out.println("⏱️ Response time: " + (System.currentTimeMillis() - start) + "ms");
}
}
}
执行结果预留位:
✅ Final result: Backup Result (slightly stale) 【备用服务兜底结果】
⏱️ Response time: 548ms
8.3 示例3:结合虚拟线程处理海量请求
场景:模拟一个高并发网关,需要同时处理成千上万个对外部服务的调用。我们将利用虚拟线程来实现。
java
// 【插入 Example3_VirtualThreads.java,需要在JDK21或以上执行】
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.IntStream;
public class Example3_VirtualThreads {
// 创建虚拟线程
private static final ExecutorService VIRTUAL_THREAD_POOL = Executors.newVirtualThreadPerTaskExecutor();
// 模拟I/O密集型的外部服务调用(业务逻辑完全不变)
private static CompletableFuture<String> callExternalService(int id) {
return CompletableFuture.supplyAsync(() -> {
// 模拟网络I/O等待 100ms
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// 正确处理中断异常:恢复中断标记 + 日志,不吞异常
System.err.println("Virtual Thread-" + Thread.currentThread().threadId() + " 被中断, requestId=" + id);
//e.printStackTrace();
Thread.currentThread().interrupt();
}
return "Response from service " + id;
}, VIRTUAL_THREAD_POOL);
}
public static void main(String[] args) {
int totalRequests = 10_000; // 1万并发IO请求
long start = System.currentTimeMillis();
// 创建1万个异步虚拟线程任务
CompletableFuture<?>[] futures = IntStream.range(0, totalRequests)
.mapToObj(Example3_VirtualThreads::callExternalService)
.toArray(CompletableFuture[]::new);
// 等待所有IO请求完成
CompletableFuture.allOf(futures).join();
long end = System.currentTimeMillis();
// 输出耗时统计
System.out.println("✅ Success! Processed " + totalRequests + " IO requests in " + (end - start) + "ms");
// ✅ 这里可以安全调用shutdown()!!!
VIRTUAL_THREAD_POOL.shutdown();
}
}
执行结果预留位:
✅ Success! Processed 10000 IO requests in 157ms
8.4 示例4:完整的异常处理链
场景:在一个支付流程中,调用银行接口可能会失败。我们需要优雅地处理异常,并提供清晰的错误信息。
java
// 【插入 Example4_ExceptionHandling.java】
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
public class Example4_ExceptionHandling {
// 模拟一个不稳定的银行支付接口
private static CompletableFuture<Boolean> processPayment(double amount) {
return CompletableFuture.supplyAsync(() -> {
if (amount > 1000) {
throw new IllegalArgumentException("Amount too high!");
}
// 模拟支付成功
return true;
});
}
public static void main(String[] args) {
CompletableFuture<String> paymentResult = processPayment(1500.0)
.handle((success, ex) -> {
if (ex != null) {
// 解包CompletionException以获取原始异常
Throwable cause = ex instanceof CompletionException ? ex.getCause() : ex;
return "Payment failed: " + cause.getMessage();
} else {
return "Payment successful!";
}
});
System.out.println(paymentResult.join());
}
}
执行结果预留位:
Payment failed: Amount too high!
9. 结语:CompletableFuture不是银弹,但它是异步编程的利器
CompletableFuture 极大地简化了 Java 中的异步编程和并发任务编排。它让我们能够以声明式的方式构建复杂的异步逻辑,代码可读性和可维护性都得到了显著提升。
从 Future 的被动等待,到 CompletableFuture 的主动编排,再到与虚拟线程的珠联璧合,Java 的异步编程能力已经达到了一个新的高度。我们现在可以用接近同步代码的简洁性,写出性能媲美传统异步非阻塞模型的高并发程序。
正确使用 CompletableFuture 的时机:
- 需要组合多个异步任务(
allOf,anyOf)。 - 需要清晰的链式调用和回调处理。
- 构建基于 RPC 或 REST API 调用的微服务应用。
不要过度使用的场景:
- CPU 密集型计算任务(应使用
ForkJoinPool)。 - 需要处理背压的无限数据流(应考虑 Reactive Streams)。
掌握 CompletableFuture,是你迈向高并发、高性能 Java 开发的必经之路。
10. 经典书籍推荐
-
《Java并发编程实战》(Java Concurrency in Practice)
- 作者:Brian Goetz 等
- 价值 :尽管出版较早,但这本书依然是 Java 并发领域的圣经。它奠定了现代 Java 并发编程的理论基础,书中关于
Future的讨论是理解CompletableFuture的重要基石。
-
《Java Performance Companion》
- 作者:Charlie Hunt, Monica Beckwith, et al.
- 价值 :这本书深入探讨了 Java 性能调优的各个方面,包括最新的垃圾回收器和 Project Loom(虚拟线程)。对于想深入理解
CompletableFuture与虚拟线程结合后性能表现的开发者来说,是不可多得的参考资料。
11. 下一篇预告
在掌握了异步协作 (CountDownLatch, CyclicBarrier, Phaser) 和异步任务编排 (CompletableFuture) 之后,我们将在下一篇中探讨如何控制并发访问的资源数量 。敬请期待:【Java线程安全实战】⑩ 信号量的艺术:Semaphore 如何成为系统的"流量阀门"?
12. 往期博客回顾
- 【Java线程安全实战】① 从ArrayList并发翻车说起:2025年主流线程安全集合全景图解
- 【Java线程安全实战】② ConcurrentHashMap 源码深度拆解:如何做到高性能并发?
- 【Java线程安全实战】③ ThreadLocal 源码深度拆解:如何做到线程隔离?
- 【Java线程安全实战】④ 可重入锁ReentrantLock深度拆解:如何实现线程安全的同步?
- 【Java线程安全实战】⑤ 原子类(Atomic)深度解析:无锁编程(Lock-Free)的终极奥义
- 【Java线程安全实战】⑥ 秒级达百万高并发框架-Disruptor:揭秘LMAX的"快递小哥"如何让系统跑得更快
- 【Java线程安全实战】⑦ 线程间协作的艺术:CountDownLatch 与 CyclicBarrier 深度剖析
- 【Java线程安全实战】⑧ 阶段同步的艺术:Phaser 与 Condition 的高阶玩法