异步线程深度剖析(CompletableFuture/异步模式/虚拟线程)
一、CompletableFuture 源码深度解析
1.1 核心数据结构
java
public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {
/**
* 结果字段 - volatile 保证可见性
*
* 状态:
* - null: 未完成
* - NIL: 完成但无结果(用于 CompletableFuture<Void>)
* - AltResult: 完成但有异常
* - 其他: 正常结果
*/
volatile Object result;
/**
* 依赖的 Completion 栈
*
* 结构:单向链表
* 每个 Completion 代表一个依赖任务
*
* 类型:
* - UniCompletion: 单依赖(thenApply、thenAccept)
* - BiCompletion: 双依赖(thenCombine、thenAcceptBoth)
* - Signaller: 终结操作(whenComplete、handle、exceptionally)
*/
volatile Completion stack;
// NIL 对象(表示完成但无结果)
static final Object NIL = new Object();
// 内部类:异常结果包装
static final class AltResult {
final Throwable ex;
AltResult(Throwable ex) { this.ex = ex; }
}
}
1.2 Completion 栈结构
java
/**
* Completion 基类
*
* 设计思想:
* 1. 使用栈(LIFO)而不是队列
* 2. 每个 Completion 包含:依赖的 Future + 执行动作
* 3. 完成时遍历栈,触发所有依赖
*/
static abstract class Completion {
Completion next; // 指向下一个依赖(栈结构)
/**
* 尝试触发
* @return true 表示已触发,false 表示等待其他依赖
*/
abstract boolean tryFire(int mode);
/**
* 是否可触发
*/
abstract boolean isDone();
}
/**
* 单依赖 Completion
*
* 用于:thenApply、thenAccept、thenRun
*/
static final class UniCompletion extends Completion {
Executor executor; // 执行器
CompletableFuture<?> dep; // 依赖的 Future
CompletableFuture<?> src; // 源 Future
UniCompletion(Executor e, CompletableFuture<?> dep, CompletableFuture<?> src) {
this.executor = e;
this.dep = dep;
this.src = src;
}
}
/**
* UniApply - thenApply 的实现
*/
static final class UniApply<T> extends UniCompletion {
Function<Object, ? extends T> fn;
UniApply(Executor e, CompletableFuture<T> dep, CompletableFuture<?> src,
Function<Object, ? extends T> fn) {
super(e, dep, src);
this.fn = fn;
}
@Override
final boolean tryFire(int mode) {
CompletableFuture<T> d; CompletableFuture<?> a;
// 检查是否可以触发
if ((d = dep) == null || !d.uniApply(a = src, fn, mode > 0))
return false;
// 触发后清理
dep = null; src = null; fn = null;
return true;
}
}
1.3 complete 方法源码
java
/**
* 完成 Future
*
* @param value 结果值
* @return true 表示成功完成,false 表示已完成
*/
public boolean complete(T value) {
// 1. 设置结果
boolean triggered = completeValue(value);
// 2. 触发所有依赖
postComplete();
return triggered;
}
/**
* 设置结果值
*/
private boolean completeValue(Object value) {
// CAS 设置结果
// 如果 result 已经是非 null,说明已完成
return UNSAFE.compareAndSwapObject(this, RESULT, null,
value == null ? NIL : value);
}
/**
* 触发所有依赖任务
*
* 核心逻辑:
* 1. 遍历 Completion 栈
* 2. 对每个 Completion 调用 tryFire
* 3. 如果 tryFire 返回 true,说明已触发
* 4. 如果返回 false,说明需要等待其他依赖
*/
final void postComplete() {
for (Completion t = stack; t != null; ) {
Completion next = t.next;
// 尝试触发
if (!t.tryFire(0)) {
// 未触发,可能是异步执行
// 将 t 加入执行队列
if (t instanceof UniCompletion) {
UniCompletion u = (UniCompletion) t;
if (u.executor != null) {
u.executor.execute(() -> u.tryFire(1));
}
}
}
t = next;
}
}
1.4 thenApply 源码
java
/**
* 同步转换结果
*
* @param fn 转换函数
* @return 新的 CompletableFuture
*/
public <U> CompletableFuture<U> thenApply(Function<? super T, ? extends U> fn) {
return uniApplyStage(null, fn);
}
/**
* thenApply 核心实现
*/
private <U> CompletableFuture<U> uniApplyStage(Executor e,
Function<? super T, ? extends U> fn) {
if (fn == null) throw new NullPointerException();
CompletableFuture<U> d = new CompletableFuture<U>();
// 检查是否已完成
if (e != null || !d.uniApply(this, fn, null)) {
// 未完成或需要异步执行
// 创建 UniApply Completion 加入栈
UniApply<T> c = new UniApply<T>(e, d, this, fn);
pushCompletion(c);
}
return d;
}
/**
* 执行 uni 转换
*
* @param mode 0=同步,>0=异步,<0=检查
*/
final <U> boolean uniApply(CompletableFuture<?> a,
Function<Object, ? extends U> f, int mode) {
Object r;
// 检查源 Future 是否完成
if ((r = a.result) == null)
return false; // 未完成
// 检查是否有异常
if (r instanceof AltResult) {
Throwable ex = ((AltResult) r).ex;
if (ex != null) {
// 传播异常
completeExceptionally(ex);
return true;
}
}
// 执行转换函数
try {
@SuppressWarnings("unchecked")
T value = (T) (r == NIL ? null : r);
U result = f.apply(value);
complete(result);
} catch (Throwable ex) {
completeExceptionally(ex);
}
return true;
}
二、异步编程模式
2.1 回调模式
java
// 回调模式(Callback)
public class CallbackPattern {
// 定义回调接口
interface Callback<T> {
void onSuccess(T result);
void onFailure(Throwable error);
}
// 异步方法
public void getUserAsync(Long userId, Callback<User> callback) {
CompletableFuture.supplyAsync(() -> {
// 模拟耗时操作
return userService.getUser(userId);
}).whenComplete((result, error) -> {
if (error != null) {
callback.onFailure(error);
} else {
callback.onSuccess(result);
}
});
}
// 使用
public void example() {
getUserAsync(1L, new Callback<User>() {
@Override
public void onSuccess(User result) {
System.out.println("用户: " + result.getName());
}
@Override
public void onFailure(Throwable error) {
System.out.println("失败: " + error.getMessage());
}
});
}
}
2.2 Future 模式
java
// Future 模式
public class FuturePattern {
public void example() {
// 提交异步任务
Future<User> future = executor.submit(() -> {
return userService.getUser(1L);
});
// 做其他事情...
doOtherWork();
// 获取结果(阻塞)
try {
User user = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
// 超时处理
future.cancel(true);
}
}
}
2.3 Promise 模式
java
// Promise 模式(CompletableFuture 实现)
public class PromisePattern {
public CompletableFuture<User> getUserPromise(Long userId) {
CompletableFuture<User> promise = new CompletableFuture<>();
executor.submit(() -> {
try {
User user = userService.getUser(userId);
promise.complete(user); // 完成 Promise
} catch (Exception e) {
promise.completeExceptionally(e); // 异常完成
}
});
return promise;
}
// 链式调用
public CompletableFuture<Order> createOrder(Long userId) {
return getUserPromise(userId)
.thenApply(user -> {
// 用户信息获取后,创建订单
return orderService.create(user);
})
.thenApply(order -> {
// 订单创建后,发送通知
notificationService.send(order);
return order;
});
}
}
三、异步编排实战
3.1 并行任务编排
java
/**
* 商品详情页 - 并行获取多个数据源
*/
public CompletableFuture<ProductDetailVO> getProductDetail(Long productId) {
// 1. 并行获取基础数据
CompletableFuture<Product> productFuture =
CompletableFuture.supplyAsync(() -> productService.getById(productId));
CompletableFuture<List<Comment>> commentsFuture =
CompletableFuture.supplyAsync(() -> commentService.list(productId));
CompletableFuture<Stock> stockFuture =
CompletableFuture.supplyAsync(() -> stockService.get(productId));
CompletableFuture<Recommendation> recommendFuture =
CompletableFuture.supplyAsync(() -> recommendService.get(productId));
// 2. 等待所有完成
CompletableFuture<Void> allDone = CompletableFuture.allOf(
productFuture, commentsFuture, stockFuture, recommendFuture
);
// 3. 组合结果
return allDone.thenApply(v -> {
ProductDetailVO vo = new ProductDetailVO();
vo.setProduct(productFuture.join());
vo.setComments(commentsFuture.join());
vo.setStock(stockFuture.join());
vo.setRecommendation(recommendFuture.join());
return vo;
});
}
/**
* 带超时的并行获取
*/
public CompletableFuture<ProductDetailVO> getProductDetailWithTimeout(Long productId) {
CompletableFuture<ProductDetailVO> future = getProductDetail(productId);
// 设置超时
return future.orTimeout(3, TimeUnit.SECONDS)
.exceptionally(e -> {
if (e instanceof TimeoutException) {
log.warn("获取商品详情超时");
return ProductDetailVO.defaultVO();
}
throw new CompletionException(e);
});
}
3.2 串行 + 并行混合编排
java
/**
* 下单流程:串行 + 并行
*
* 流程:
* 1. 校验库存(串行)
* 2. 计算优惠 + 计算运费(并行)
* 3. 创建订单(串行)
* 4. 扣减库存 + 发送通知(并行)
*/
public CompletableFuture<Order> createOrder(OrderRequest request) {
// 1. 校验库存
return stockService.check(request.getProductId(), request.getQuantity())
.thenCompose(stock -> {
// 2. 并行:计算优惠 + 计算运费
CompletableFuture<Discount> discountFuture =
discountService.calculate(request);
CompletableFuture<Freight> freightFuture =
freightService.calculate(request);
return discountFuture.thenCombine(freightFuture, (discount, freight) -> {
// 3. 创建订单
return orderService.create(request, discount, freight);
});
})
.thenCompose(order -> {
// 4. 并行:扣减库存 + 发送通知
CompletableFuture<Void> stockFuture =
stockService.deduct(order).thenApply(v -> null);
CompletableFuture<Void> notifyFuture =
notificationService.send(order).thenApply(v -> null);
return stockFuture.thenCombine(notifyFuture, (v1, v2) -> order);
});
}
3.3 异常处理
java
/**
* 异常处理最佳实践
*/
public CompletableFuture<User> getUserWithFallback(Long userId) {
return CompletableFuture.supplyAsync(() -> {
return userService.getUser(userId);
})
// 捕获特定异常
.exceptionally(e -> {
if (e.getCause() instanceof TimeoutException) {
log.warn("获取用户超时,使用缓存");
return cacheService.getUser(userId);
}
throw new CompletionException(e);
})
// 统一异常处理
.handle((result, error) -> {
if (error != null) {
log.error("获取用户失败", error);
return User.defaultUser();
}
return result;
});
}
四、虚拟线程(Virtual Threads)
4.1 虚拟线程原理
yaml
虚拟线程 vs 平台线程:
┌─────────────────────────────────────────────────────────────┐
│ 平台线程(Platform Thread) │
│ ├── 1:1 映射到操作系统线程 │
│ ├── 创建成本高(~1MB 栈空间) │
│ ├── 数量受限(通常 < 1000) │
│ └── 阻塞时占用 OS 线程 │
├─────────────────────────────────────────────────────────────┤
│ 虚拟线程(Virtual Thread) │
│ ├── M:N 映射(多个虚拟线程复用少量载体线程) │
│ ├── 创建成本低(~几 KB) │
│ ├── 数量可达百万级 │
│ └── 阻塞时自动切换载体线程 │
└─────────────────────────────────────────────────────────────┘
虚拟线程调度:
┌─────────────────────────────────────────────────────────────┐
│ 虚拟线程 T1 执行 │
│ ├── 执行同步代码 → 在载体线程 C1 上运行 │
│ ├── 遇到阻塞(IO/锁)→ 从 C1 卸载,保存状态 │
│ ├── 载体线程 C1 执行其他虚拟线程 T2 │
│ ├── T1 阻塞结束 → 加入调度队列 │
│ └── 载体线程 C1/C2 从队列取出 T1 继续执行 │
└─────────────────────────────────────────────────────────────┘
4.2 虚拟线程使用
java
// JDK 21+ 虚拟线程
public class VirtualThreadDemo {
// 创建虚拟线程
public void createVirtualThread() {
Thread.startVirtualThread(() -> {
System.out.println("Hello from virtual thread!");
System.out.println("Thread: " + Thread.currentThread());
});
}
// 使用 ExecutorService
public void executorDemo() {
// 创建虚拟线程执行器
try (ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor()) {
// 提交 100 万个任务
for (int i = 0; i < 1_000_000; i++) {
executor.submit(() -> {
// 模拟 IO 操作
Thread.sleep(Duration.ofSeconds(1));
return "done";
});
}
}
// 所有任务完成后关闭
}
// 虚拟线程 + CompletableFuture
public CompletableFuture<String> asyncWithVirtualThread() {
return CompletableFuture.supplyAsync(() -> {
// 这段代码会在虚拟线程中执行
return fetchData();
}, Executors.newVirtualThreadPerTaskExecutor());
}
}
4.3 虚拟线程 vs 协程
bash
虚拟线程 vs 协程对比:
┌─────────────┬────────────────┬────────────────┐
│ 特性 │ 虚拟线程 │ 协程(Kotlin) │
├─────────────┼────────────────┼────────────────┤
│ 语言支持 │ Java 原生 │ Kotlin 标准库 │
│ 语法 │ 普通线程 API │ suspend/async │
│ 调度 │ JVM 调度 │ 编译器 + 运行时 │
│ 阻塞兼容 │ 支持 │ 不支持(需转换)│
│ 性能 │ 接近协程 │ 略优 │
│ 学习成本 │ 低 │ 中 │
└─────────────┴────────────────┴────────────────┘
选择建议:
├── Java 项目:虚拟线程(无需改代码风格)
├── Kotlin 项目:协程(语法更优雅)
└── 高并发 IO:两者性能接近
五、异步编程最佳实践
5.1 线程池配置
java
// 异步任务线程池配置
@Configuration
public class AsyncConfig {
@Bean("asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
// 核心参数
executor.setCorePoolSize(20); // CPU 核数 * 2
executor.setMaxPoolSize(100); // 根据任务量调整
executor.setQueueCapacity(1000); // 队列大小
executor.setKeepAliveSeconds(60); // 空闲超时
// 线程命名
executor.setThreadNamePrefix("async-");
// 拒绝策略
executor.setRejectedExecutionHandler((r, e) -> {
log.warn("异步任务被拒绝: {}", r);
// 降级:由调用线程执行
r.run();
});
// 优雅关闭
executor.setWaitForTasksToCompleteOnShutdown(true);
executor.setAwaitTerminationSeconds(60);
executor.initialize();
return executor;
}
}
// 使用
@Service
public class AsyncService {
@Async("asyncExecutor")
public CompletableFuture<User> getUserAsync(Long userId) {
return CompletableFuture.completedFuture(
userService.getUser(userId)
);
}
}
5.2 避免的陷阱
java
// 陷阱1:阻塞虚拟线程
// 错误:在虚拟线程中使用 synchronized
synchronized (lock) {
// 虚拟线程被阻塞,载体线程也被占用
doBlockingIO();
}
// 正确:使用 ReentrantLock
lock.lock();
try {
doBlockingIO();
} finally {
lock.unlock();
}
// 陷阱2:CompletableFuture 链式阻塞
future.thenApply(r1 -> {
// 这里会阻塞当前线程
return blockingCall(); // 错误!
}).thenApply(r2 -> ...);
// 正确:使用 thenCompose
future.thenCompose(r1 -> {
return CompletableFuture.supplyAsync(() -> blockingCall());
}).thenApply(r2 -> ...);
// 陷阱3:忘记处理异常
future.thenApply(r -> process(r));
// 如果 future 异常,这里不会执行,异常被吞掉
// 正确:处理异常
future.thenApply(r -> process(r))
.exceptionally(e -> {
log.error("处理失败", e);
return defaultValue();
});
六、面试题精选
Q1:CompletableFuture 的原理?
基于 Completion 栈,完成时遍历栈触发所有依赖任务
Q2:CompletableFuture 如何并行?
allOf 等待所有,anyOf 等待任一,thenCombine 组合结果
Q3:虚拟线程和平台线程的区别?
虚拟线程 M:N 映射,创建成本低,数量可达百万级
Q4:虚拟线程阻塞时会发生什么?
从载体线程卸载,保存状态,阻塞结束后加入调度队列
Q5:异步编程如何避免回调地狱?
使用 CompletableFuture 链式调用
Q6:@Async 的原理?
Spring AOP 代理,将方法调用提交到线程池
Q7:异步任务如何设置超时?
orTimeout 或 get(timeout)
Q8:异步任务异常如何处理?
exceptionally 捕获,handle 统一处理
Q9:虚拟线程适合什么场景?
IO 密集型(HTTP 调用、数据库查询、文件读写)
Q10:异步线程池如何配置?
根据任务类型设置核心线程数、队列大小、拒绝策略