Java 8 引入的 CompletableFuture
是并发编程中处理异步任务的核心工具,它通过实现 Future
和 CompletionStage
接口,提供了链式调用、任务组合、异常处理等强大功能。本文将结合源码,深入解析其核心机制、设计模式,并给出常见使用场景与代码示例。
一、核心架构:状态管理与依赖任务
CompletableFuture
的核心目标是将异步任务的完成状态与依赖操作解耦,允许通过链式调用定义任务完成后的行为(如计算、消费、异常处理等)。其内部通过以下关键字段实现状态管理和依赖触发:
1.1 状态与结果存储:result
字段
volatile Object result; // 存储任务结果或异常(AltResult类型)
- 正常结果:直接存储结果值(若为
null
则用NIL
包装)。 - 异常结果:通过
AltResult
类包装异常(如CompletionException
)。 - 原子性:通过
UNSAFE.compareAndSwapObject
实现原子性状态更新(如completeValue
、completeThrowable
方法)。
1.2 依赖任务栈:stack
字段
volatile Completion stack; // Treiber 栈结构,存储依赖的Completion任务
stack
是一个无锁的 Treiber
栈,用于存储所有依赖当前任务的后续操作(如 thenApply
、thenAccept
等定义的任务)。每个依赖任务是 Completion
接口的实现类(如 UniApply
、BiApply
),通过 next
字段链接成栈。
1.3 任务触发:postComplete
方法
当当前任务完成(正常或异常)时,postComplete
方法会被调用,遍历 stack
栈并触发所有依赖任务:
final void postComplete() {
CompletableFuture<?> f = this; Completion h;
while ((h = f.stack) != null || (f != this && (h = (f = this).stack) != null)) {
if (f.casStack(h, h.next)) { // 原子弹出栈顶任务
h.tryFire(NESTED); // 触发任务执行
f = (h.tryFire(NESTED) == null) ? this : h.dep; // 递归处理依赖
}
}
}
- 无锁遍历:通过
casStack
原子操作弹出栈顶任务,避免锁竞争。 - 递归触发:每个
Completion
任务的tryFire
方法执行后,可能触发其依赖任务的postComplete
,形成级联触发。
二、关键机制解析
2.1 异步任务执行策略
CompletableFuture
的异步方法(如 thenApplyAsync
)默认使用 ForkJoinPool.commonPool()
执行任务,若并行度不足则回退到单线程:
private static final boolean useCommonPool = (ForkJoinPool.getCommonPoolParallelism() > 1);
private static final Executor asyncPool = useCommonPool ? ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();
static class ThreadPerTaskExecutor implements Executor {
public void execute(Runnable r) { new Thread(r).start(); } // 单线程执行器
}
- 策略选择:通过
useCommonPool
动态选择执行器,平衡资源利用率和任务并行度。 - 扩展性:用户可通过传入自定义
Executor
覆盖默认策略(如thenApplyAsync(fn, executor)
)。
2.2 依赖任务的类型与执行
CompletableFuture
支持多种依赖任务类型,通过内部类 UniCompletion
(单输入)和 BiCompletion
(双输入)实现:
2.2.1 单输入任务(UniCompletion
)
处理单个前置任务的完成事件,例如 thenApply
:
abstract static class UniCompletion<T,V> extends Completion {
Executor executor; // 任务执行器(可能为null)
CompletableFuture<V> dep; // 当前任务的依赖(即下一个阶段)
CompletableFuture<T> src; // 前置任务(当前阶段的源)
final boolean claim() { // 原子声明任务所有权(避免重复执行)
if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
if (executor == null) return true; // 同步执行
executor.execute(this); // 异步执行
}
return false;
}
}
- 原子声明:通过
ForkJoinTask
的tag
字段原子标记任务是否已被认领,避免多线程重复执行。 - 执行模式:若
executor
为null
(同步模式),直接执行;否则异步提交到执行器。
2.2.2 双输入任务(BiCompletion
)
处理两个前置任务的完成事件,例如 thenCombine
:
abstract static class BiCompletion<T,U,V> extends UniCompletion<T,V> {
CompletableFuture<U> snd; // 第二个前置任务
}
双输入任务需要等待两个前置任务均完成(或任一完成,取决于具体方法),通过 CoCompletion
类协调两个前置任务的触发:
static final class CoCompletion extends Completion {
BiCompletion<?,?,?> base; // 指向基础双输入任务
final CompletableFuture<?> tryFire(int mode) {
return base.tryFire(mode); // 委托给基础任务执行
}
}
2.3 异常处理与传播
CompletableFuture
的异常处理通过 completeExceptionally
方法触发,异常会被包装为 CompletionException
并传播给依赖任务:
final boolean completeThrowable(Throwable x) {
return UNSAFE.compareAndSwapObject(this, RESULT, null, encodeThrowable(x));
}
static AltResult encodeThrowable(Throwable x) {
return new AltResult((x instanceof CompletionException) ? x : new CompletionException(x));
}
- 异常传播:依赖任务(如
exceptionally
)会检测到前置任务的异常结果,并执行相应的恢复逻辑。 - 用户友好性:
get()
方法抛出ExecutionException
(兼容Future
接口),而join()
直接抛出CompletionException
(更简洁)。
三、设计模式深度解析
CompletableFuture
的源码中巧妙融合了多种设计模式,使其具备高度的灵活性和可扩展性。
3.1 观察者模式(Observer Pattern)
核心体现:CompletableFuture
的依赖任务的注册与触发机制。
- 主题(Subject):当前
CompletableFuture
实例(任务完成状态变化)。 - 观察者(Observer):所有注册到
stack
中的Completion
任务(依赖任务)。 - 通知机制:任务完成时(
postComplete
)遍历观察者(stack
栈)并触发其tryFire
方法。
示例:调用 thenApply(fn)
时,会创建一个 UniApply
观察者并注册到当前任务的 stack
中。当前任务完成后,postComplete
触发 UniApply.tryFire
,执行 fn
并完成依赖任务。
3.2 模板方法模式(Template Method Pattern)
核心体现:Completion
及其子类的 tryFire
方法。
Completion
定义了模板方法 tryFire
,子类(如 UniApply
、BiApply
)实现具体逻辑:
abstract static class Completion extends ForkJoinTask<Void> implements Runnable {
abstract CompletableFuture<?> tryFire(int mode); // 模板方法(核心逻辑)
public final void run() { tryFire(ASYNC); } // 固定流程(异步执行)
}
static final class UniApply<T,V> extends UniCompletion<T,V> {
final CompletableFuture<V> tryFire(int mode) { // 具体实现
// 执行fn并完成依赖任务
}
}
- 模板方法:
tryFire
定义核心执行逻辑,子类(如UniApply
、UniAccept
)实现具体行为。 - 统一接口:
run()
方法统一异步执行入口,调用tryFire(ASYNC)
。
3.3 策略模式(Strategy Pattern)
核心体现:异步任务的执行策略(Executor
接口)。
CompletableFuture
的异步方法(如 thenApplyAsync
)默认使用 ForkJoinPool.commonPool()
,用户可通过自定义 Executor
替换默认策略:
private static final Executor asyncPool = ...; // 默认策略(ForkJoinPool或单线程)
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor) {
return uniApplyStage(screenExecutor(executor), fn); // 允许传入自定义Executor
}
- 策略接口:
Executor
定义任务执行策略(execute(Runnable)
)。 - 动态切换:用户可通过
thenApplyAsync(fn, executor)
传入自定义执行器(如ThreadPoolExecutor
),替换默认的asyncPool
,适应不同场景需求(如高并发、低延迟)。
3.4 责任链模式(Chain of Responsibility)
核心体现:链式调用(如 thenApply().thenAccept().exceptionally()
)通过 Completion
任务的级联触发实现责任链。
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello")
.thenApply(s -> s + " world") // 第一个Completion(UniApply)
.thenAccept(s -> System.out.println(s)) // 第二个Completion(UniAccept)
.exceptionally(e -> { /* 异常处理 */ }); // 第三个Completion(UniExceptionally)
每个 thenXxx
方法生成一个新的 CompletableFuture
,并将其依赖任务(Completion
)注册到前一个阶段的 stack
中。当前阶段完成后,触发下一个阶段的任务,形成链式调用。
四、关键方法源码解析
4.1 supplyAsync
:异步任务提交
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
return asyncSupplyStage(asyncPool, supplier);
}
private static <U> CompletableFuture<U> asyncSupplyStage(Executor e, Supplier<U> f) {
CompletableFuture<U> d = new CompletableFuture<U>();
e.execute(new AsyncSupply<U>(d, f)); // 提交任务到执行器
return d;
}
static final class AsyncSupply<T> extends ForkJoinTask<Void> implements Runnable {
CompletableFuture<T> dep;
Supplier<T> fn;
public void run() {
if (dep.result == null) { // 避免重复执行
try {
dep.completeValue(fn.get()); // 执行Supplier并设置结果
} catch (Throwable ex) {
dep.completeThrowable(ex); // 异常处理
}
}
}
}
- 异步执行:通过
Executor
提交AsyncSupply
任务,执行Supplier
并设置结果。 - 原子性:通过
dep.result == null
检查避免重复执行(如任务已被取消)。
4.2 thenApply
:任务转换
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {
return uniApplyStage(null, fn); // 同步模式(无Executor)
}
private <V> CompletableFuture<V> uniApplyStage(Executor e, Function<? super T,? extends V> f) {
CompletableFuture<V> d = new CompletableFuture<V>();
if (e != null || !d.uniApply(this, f, null)) { // 若需异步或当前任务未完成
UniApply<T,V> c = new UniApply<>(e, d, this, f); // 创建UniApply任务
push(c); // 注册到当前任务的stack中
c.tryFire(SYNC); // 尝试同步触发(若当前任务已完成)
}
return d;
}
- 同步触发:若当前任务已完成(
this.result != null
),直接执行fn
并完成依赖任务d
。 - 异步注册:若当前任务未完成,将
UniApply
任务注册到this.stack
中,等待当前任务完成后触发。
五、常见使用场景与代码示例
CompletableFuture
广泛应用于异步计算、多任务组合、异常处理等场景,以下是典型示例:
3.1 异步任务提交与链式处理
场景:异步获取数据并处理。
import java.util.concurrent.CompletableFuture;
public class AsyncDemo {
public static void main(String[] args) {
// 异步获取用户ID
CompletableFuture<Integer> userIdFuture = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(100); // 模拟耗时操作
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return 1001;
});
// 链式处理:根据用户ID获取用户名
CompletableFuture<String> userNameFuture = userIdFuture
.thenApply(userId -> "User-" + userId)
.exceptionally(e -> { // 异常处理
System.err.println("Error: " + e.getMessage());
return "Unknown";
});
// 阻塞等待结果
System.out.println("Username: " + userNameFuture.join()); // 输出:User-1001
}
}
3.2 多任务组合(allOf
/anyOf
)
场景:等待多个任务完成(allOf
)或任一任务完成(anyOf
)。
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;
public class CombineTasksDemo {
public static void main(String[] args) {
// 任务1:查询订单
CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Order-202310";
});
// 任务2:查询物流
CompletableFuture<String> logisticsFuture = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(150);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
return "Delivered";
});
// 等待所有任务完成
CompletableFuture<Void> allTasks = CompletableFuture.allOf(orderFuture, logisticsFuture);
allTasks.join();
System.out.println("Order: " + orderFuture.join()); // 输出:Order-202310
System.out.println("Logistics: " + logisticsFuture.join()); // 输出:Delivered
// 等待任一任务完成(示例:anyOf)
CompletableFuture<Object> anyTask = CompletableFuture.anyOf(orderFuture, logisticsFuture);
Object result = anyTask.get(200, TimeUnit.MILLISECONDS); // 物流任务先完成
System.out.println("First completed: " + result); // 输出:Delivered
}
}
3.3 异常处理与恢复
场景:任务执行失败时,使用默认值或备用逻辑恢复。
import java.util.concurrent.CompletableFuture;
public class ExceptionHandlingDemo {
public static void main(String[] args) {
CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("Simulated error"); // 模拟异常
}).exceptionally(e -> { // 异常处理
System.err.println("Recovering from error: " + e.getMessage());
return 0; // 默认值
});
System.out.println("Result: " + future.join()); // 输出:Result: 0
}
}
六、总结
CompletableFuture
通过无锁状态管理(result
和 stack
)、依赖任务的级联触发(postComplete
)和灵活的异步策略(Executor
),实现了强大的异步编程能力。其设计融合了观察者模式(依赖触发)、模板方法模式(任务执行流程)、策略模式(异步执行器)和责任链模式(链式调用),是并发编程中“组合优于继承”“依赖倒置”等设计原则的典范。深入理解其源码,对优化异步任务设计、定位并发问题及掌握现代Java并发编程至关重要。