CompletionStage 接口说明见 Java异步编程:CompletionStage接口详解-CSDN博客
基本流程理解见:揭秘 CompletedFuture 的设计精髓(基础)-CSDN博客
成员变量:
volatile Object result
AltResult
封装)。null
编码为 NIL
)。AltResult
包装(如 new AltResult(ex)
)。RESULT.compareAndSet(this, null, r)
实现无锁更新。volatile Completion stack
Completion
)按 LIFO 顺序触发。Completion
类型:
UniCompletion
):如 thenApply
、thenAccept
。BiCompletion
):如 thenCombine
、thenAcceptBoth
。Signaller
):用于阻塞等待线程(如 get() 的阻塞唤醒)。Treiber 栈,实际上可以理解为一个 从头部CAS插入和删除的链表
Completion
是一个链表节点,有next
字段。
stack
是一个由Completion.next
构成的单向链表(栈),如下:
stack → C3 → C2 → C1 → null
每个 Completion 节点代表一个未执行的操作(如
thenApply
),一旦完成就从栈中弹出并执行。
实际上,CompletableFuture形成了一个有向无环图(DAG)结构:
每个CompletableFuture都有自己的stack,存储依赖于它的Completion链表。
Completion
Completion
作为 CompletableFuture
的依赖操作载体,通过 Treiber 栈组织依赖关系,结合无锁化和异步触发机制,实现了高效的异步任务流水线。其子类(如 UniApply
、BiApply
)针对不同场景封装逻辑,而 tryFire
和 postComplete
构成了核心的触发链路。
继承关系:
abstract static class Completion extends ForkJoinTask
ForkJoinTask
,支持异步任务提交(通过 ForkJoinPool
)。Runnable
,可直接被线程池执行(如 executor.execute(completion)
)。AsynchronousCompletionTask
是标记接口,用于调试和监控。关键字段与方法:
volatile Completion next; // Treiber栈的链表指针
abstract CompletableFuture> tryFire(int mode); // 触发依赖操作
abstract boolean isLive(); // 判断节点是否有效
next
:构建 Treiber 栈结构,链式存储依赖关系。tryFire
:核心抽象方法,由子类实现具体逻辑(如应用函数、合并结果等)。isLive
:用于清理无效节点(如已取消的任务)Completion
的子类分为两类:单源依赖(UniCompletion
)和多源依赖(BiCompletion
)。
(1) 单源依赖:UniCompletion
abstract static class UniCompletion extends Completion {
Executor executor; // 执行器(可能为null)
CompletableFuture dep; // 依赖此操作的目标CompletableFuture
CompletableFuture src; // 源CompletableFuture
// ...
}
典型子类:
UniApply
:对应 thenApply
,应用函数 Function
。UniAccept
:对应 thenAccept
,消费结果 Consumer
。UniRun
:对应 thenRun
,执行 Runnable
。触发流程:
src
(源)完成时,调用 tryFire
: if (src.result != null && dep.result == null) {
d.completeValue(fn.apply(src.result)); // 执行函数并完成依赖
}
(2) 双源依赖:BiCompletion
java
abstract static class BiCompletion
典型子类:
BiApply
:对应 thenCombine
,合并两个结果 BiFunction
。BiAccept
:对应 thenAcceptBoth
,双消费 BiConsumer
。BiRun
:对应 runAfterBoth
,双源完成后执行 Runnable
。触发流程:
src
和 snd
)是否均完成:if (src.result != null && snd.result != null) {
d.completeValue(fn.apply(src.result, snd.result));
}
Completion
和 CompletableFuture
共同构建了一个依赖链的 Treiber 栈结构:
依赖注册:
thenApply、thenCombine
等方法时,创建对应的 Completion
节点。CompletableFuture
的 stack
(通过 unipush
或 bipush
)。void unipush(Completion c) { while (!tryPushStack(c)) { /* CAS竞争入栈 */ } }
结果触发:
complete、completeExceptionally
),调用 postComplete()
遍历栈: java
while ((h = stack) != null) {
stack = h.next; // 弹出节点
h.tryFire(SYNC); // 触发依赖操作
}
tryFire
会根据模式(SYNC、ASYNC
)决定同步执行或提交到线程池。异步执行:
Completion
包含 executor
,其 run()
方法会委托给线程池: public void run() { tryFire(ASYNC); } // 通过executor异步执行
观察者模式:
CompletableFuture
是被观察者,Completion
是观察者节点。postComplete
)。无锁栈管理:Treiber 栈通过 volatile
和 CAS(STACK.compareAndSet
)实现线程安全。
灵活的任务链:支持单源、多源、异步、异常处理等多种组合方式。
Completion
与 CompletableFuture
的嵌套关系当调用 thenApply
时,实际上会生成一个新的 CompletableFuture
作为目标 Future(dep
),用于保存当前阶段的操作结果。例如:
CompletableFuture
future.thenApply(...)
创建了一个新的 CompletableFuture
(future2
)。UniApply
的目标(dep
字段),而 future
是源(src
字段)。源 Future (future) 目标 Future (future2)
| |
v v
[stack] → [UniApply] → [UniApply.dep = future2]
UniApply
节点:
src
:源 Future(future
)。dep
:目标 Future(future2
)。fn
:用户传入的函数(s -> s.length()
)。当 future
完成时,UniApply
节点的 tryFire(...)
会执行函数,并将结果写入 future2
。此时,如果 future2
后续有 thenApply
,会继续创建新的 Completion 节点,推入 future2
的栈中。
CompletableFuture future3 = future
.thenApply(s -> s.length()) // future2
.thenApply(i -> i * 2); // future3
结构:
future → [UniApply(dep=future2)] → future2 → [UniApply(dep=future3)] → future3
执行流程:
future
完成后,触发 UniApply
节点。UniApply
执行 s -> s.length()
,结果写入 future2
。future2
完成后,触发其栈中的 UniApply
节点。UniApply
执行 i -> i * 2
,结果写入 future3
。如果多次调用就会形成一个嵌套链表,这也是postComplete为什么会那样写,因为要循环处理这样的结构需要回溯。
f2 = f1.ThenApply(a)
f3 = f2.ThenApply(b)
f4 = f1.ThenApply(c)
f5 = f4.ThenApply(c)
f1.stack → [ThenApply(dep=f4)] → [ThenApply(dep=f2)] → null
f2.stack → [ThenApply(dep=f3)] → null
f4.stack → [ThenApply(dep=f5)] → null
thenApply
全流程源码级解析CompletableFuture
thenApply
创建 UniApply
节点,推入 src.stack
。src
完成后,触发 UniApply.tryFire
,将 i.toString()
结果写入 dep
。thenApplyAsync
指定了线程池,则通过 executor.execute(node)
异步执行。thenApply
方法定义:public CompletableFuture thenApply(Function super T,? extends U> fn) {
return uniApplyStage(null, fn); // 同步执行
}
创建依赖阶段 (uniApplyStage
)
private CompletableFuture uniApplyStage(
Executor e, Function super T,? extends V> f) {
if (f == null) throw new NullPointerException();
CompletableFuture d = newIncompleteFuture(); // 创建目标Future
Object r;
if ((r = result) != null) // 源已完成的快速路径
d.uniApplyNow(r, e, f); // 直接同步执行函数
else
unipush(new UniApply(e, d, this, f)); // 创建依赖节点并入栈
return d;
}
newIncompleteFuture()
:创建目标 CompletableFuture
(dep
)。result != null
),直接同步执行函数。UniApply
节点并推入栈(unipush
)。构建 UniApply
节点
@SuppressWarnings("serial")
static final class UniApply extends UniCompletion {
Function super T,? extends V> fn;
UniApply(Executor executor, CompletableFuture dep,
CompletableFuture src,
Function super T,? extends V> fn) {
super(executor, dep, src); // 父类初始化
this.fn = fn;
}
// ...
}
UniApply
→ UniCompletion
→ Completion
。executor
:异步执行时使用的线程池(可能为 null
)。dep
:依赖此操作的目标 Future(dep
)。src
:源 Future(src
)。fn
:用户传入的函数。推入 Treiber 栈 (unipush
)
final void unipush(Completion c) {
if (c != null) {
while (!tryPushStack(c)) { // CAS竞争入栈
if (result != null) { // 源突然完成时终止循环
NEXT.set(c, null); // 清理next指针
break;
}
}
if (result != null)
c.tryFire(SYNC); // 立即触发
}
}
// CAS入栈实现
final boolean tryPushStack(Completion c) {
Completion h = stack;
NEXT.set(c, h); // c.next = h
return STACK.compareAndSet(this, h, c); // stack = c
}
STACK.compareAndSet
原子性更新栈顶。result != null
),直接触发 tryFire(SYNC)
。complete时发生了什么
源完成触发依赖 (postComplete
)
当源 Future (src
) 完成时(如调用 complete(42)
):
postComplete()
的作用是:
遍历当前 future 和其依赖 future 的 Completion 栈,依次弹出 Completion 并执行,直到所有 Completion 处理完毕。
它利用 CAS 实现无锁并发,利用栈结构支持链式 Completion,通过tryFire
触发下游操作,最终实现高效的异步回调链执行机制。
public boolean complete(T value) {
boolean triggered = completeValue(value); // CAS设置result
postComplete(); // 触发所有依赖节点
return triggered;
}
final void postComplete() {
CompletableFuture> f = this;
while ((h = f.stack) != null || (f != this && (h = (f = this).stack) != null)) {
CompletableFuture> d; Completion t;
if (STACK.compareAndSet(f, h, t = h.next)) { // 弹出栈顶
if (t != null) {
if (f != this) {
pushStack(h); // 处理嵌套依赖
continue;
}
NEXT.compareAndSet(h, t, null); // 断开链表
}
f = (d = h.tryFire(NESTED)) == null ? this : d; // 触发操作
}
}
}
h
),调用 h.tryFire(NESTED)
。tryFire
返回非空时,处理新生成的依赖链(如级联 thenApply
)。(h = f.stack) != null || (f != this && (h = (f = this).stack) != null)
是 两阶段扫描:
f
) 的栈中取 Completion;this
) 再次取一次;t != null && f != this
表示:
t != null
);f != this
);否则会导致后续 Completion 被跳过,导致任务丢失。
当 dep
完成时,需要触发 dep
自己的栈。例如:
CompletableFuture
future2
完成后,UniApply
节点的 tryFire(...)
会返回 future3
。postComplete()
会切换到 future3
的栈,继续触发后续操作。f = (d = h.tryFire(NESTED)) == null ? this : d;
d = h.tryFire(...)
:返回 dep
(如 future2
)。f = d
:切换到 dep
的栈,继续处理它的 Completion 节点。执行依赖操作 (UniApply.tryFire
)
final CompletableFuture tryFire(int mode) {
CompletableFuture d;
CompletableFuture a;
Object r; Throwable x; Function super T,? extends V> f;
if ((a = src) == null || (r = a.result) == null
|| (d = dep) == null || (f = fn) == null)
return null; // 参数未就绪时退出
try {
if (mode <= 0 && !claim()) // 检查是否可执行(CAS标记)
return null;
if (r instanceof AltResult) { // 异常处理
if ((x = ((AltResult)r).ex) != null) {
d.completeThrowable(x, r);
return d.postFire(a, mode);
}
r = null;
}
@SuppressWarnings("unchecked") T t = (T) r;
d.completeValue(f.apply(t)); // 应用函数并完成目标Future
} catch (Throwable ex) {
d.completeThrowable(ex);
}
src = null; dep = null; fn = null; // 清理引用
return d.postFire(a, mode); // 继续触发后续依赖
}
claim()
:通过 CAS 标记任务已被认领,防止重复执行。dep
。f.apply(t)
执行用户逻辑,结果写入 dep
。异步执行路径
若调用 thenApplyAsync
(指定 executor
):
public CompletableFuture thenApplyAsync(Function super T,? extends U> fn) {
return uniApplyStage(defaultExecutor(), fn); // 传递线程池
}
// UniApply执行时:
if (e != null) {
e.execute(new UniApply(null, d, this, f)); // 提交到线程池
} else {
// 同步执行(同前)
}
UniApply
作为 Runnable
被提交到线程池。run()
方法调用 tryFire(ASYNC)
,逻辑与同步模式一致。最终结果传递
d.completeValue(f.apply(t))
直接设置结果,触发 dep
的 postComplete()
。tryFire(ASYNC)
,其余逻辑相同。依赖链结构:
thenApply
创建一个 UniApply
节点,形成 Treiber 栈链。无锁化实现:
volatile
和 CAS 实现栈操作的线程安全。claim()
方法避免多个线程重复执行同一节点。异常传播:
AltResult
包装,在 tryFire
中自动传播到下游。资源管理:
src
、dep
引用,辅助 GC 回收。postFire
中调用 cleanStack()
移除无效节点。thenCombine
)的结构与执行流程示例代码:
CompletableFuture f1 = CompletableFuture.supplyAsync(() -> 100);
CompletableFuture f2 = CompletableFuture.supplyAsync(() -> "Hello");
CompletableFuture f3 = f1.thenCombine(f2, (i, s) -> s + i);
结构图:
f1.stack → [BiApply(dep=f3, snd=f2)] → null
f2.stack → [CoCompletion(base=BiApply)] → null
实现类关系:
BiApply
:处理两个源的结果,执行 BiFunction
。CoCompletion
:辅助类,指向第一个源的 Completion,用于第二个源完成后唤醒整个操作。三、thenCombine
的完整执行流程详解
f1.bipush(f2, new BiApply<>(e, d, this, b, f));
bipush(...)
内部会将 BiApply
推入 f1
的栈,并创建 CoCompletion
推入 f2
的栈。class CoCompletion extends Completion {
BiCompletion,?,?> base;
final CompletableFuture> tryFire(int mode) {
return base.tryFire(mode); // 转发给 BiApply
}
}
f2
完成时,也能触发 BiApply
。步骤 3:任意源完成都会尝试触发
当 f1
或 f2
完成时,各自调用 postComplete()
,尝试从各自的栈中取出 Completion 并执行。
以 f1
完成为例:
f1
的栈中有 BiApply
节点。BiApply.tryFire(...)
会检查 f1.result != null && f2.result != null
。fn.apply(t, s)
并完成 f3
。如果 f1
先完成,但 f2
还没完成:
if ((r instanceof AltResult && ((AltResult)r).ex != null) ||
(s instanceof AltResult && ((AltResult)s).ex != null)) {
d.completeThrowable(...); // 异常处理
} else if (r == null || s == null) {
return false; // 有一个未完成,不能执行
}
不执行,等待 f2
完成后再次触发。
双源 Completion 并不是简单的链表结构,而是一种 双向监听 + 协作完成机制。
原因:
CompletableFuture
支持 任意顺序完成,即:
f1
先完成,f2
后完成;f2
先完成,f1
后完成;设计方案:
BiApply
节点被推入 f1
的栈。CoCompletion
节点被推入 f2
的栈,指向 BiApply
。f1
完成时,检查 f2
是否也完成,若完成则执行。f2
未完成,则等待其完成后再触发。f2
完成时也会触发 CoCompletion
,再转发到 BiApply
。f1.stack → [BiApply(dep=f3, src=f1, snd=f2, fn)]
f2.stack → [CoCompletion(base=BiApply)]
当 f1
完成时:
BiApply.tryFire(...)
检查 f2
是否也完成。fn.apply(...)
, 完成 f3
。当 f2
完成时:
CoCompletion.tryFire(...)
转发到 BiApply.tryFire(...)
。f1
是否完成,若完成则执行。问题背景:
BiApply
是属于 f1
的 Completion。f2
也需要知道这个操作的存在,否则它完成时无法触发 BiApply
。解决方案:
f2
上注册一个轻量级代理节点 CoCompletion
,它不执行任何操作,只是把控制权转交给 BiApply
。class CoCompletion extends Completion {
BiCompletion,?,?> base;
final CompletableFuture> tryFire(int mode) {
return base.tryFire(mode); // 转发到 BiApply
}
final boolean isLive() { return base != null && base.dep != null; }
}
f1
完成 → 直接执行 BiApply
。f2
完成 → 触发 CoCompletion
→ 转发到 BiApply
。总体理解:
tryFire(...)
是所有 Completion 的统一入口,负责判断是否可执行,并实际执行用户逻辑。thenApply
)只需要一个 Completion 节点。thenCombine
)需要两个 Completion 节点:
BiApply
注册在第一个源上。CoCompletion
注册在第二个源上,仅转发控制权。tryFire 和 postCompletion 这两个函数之前进行过一些分析,但因为两者逻辑上是令人困惑的,所以这里做一次总结。
解释令人困惑的代码:
while ((h = f.stack) != null ||
(f != this && (h = (f = this).stack) != null)) {
CompletableFuture> d; Completion t;
if (STACK.compareAndSet(f, h, t = h.next)) {
if (t != null) {
if (f != this) {
pushStack(h); // 关键:为什么要放回去?
continue;
}
NEXT.compareAndSet(h, t, null);
}
f = (d = h.tryFire(NESTED)) == null ? this : d; // 关键:返回值含义
}
}
postComplete
方法负责在CompletableFuture完成后触发所有依赖的Completion。它的核心逻辑是:
tryFire(NESTED)
方法tryFire方法有三种模式:
NESTED模式是为了解决递归调用问题。当一个Completion完成后,可能触发其他Completion的完成,形成链式反应。如果每次都直接调用postComplete,会导致栈溢出。postComplete调用tryFire时使用NESTED模式
tryFire在NESTED模式下
情况1:返回null。表示这个Completion处理完毕,没有需要继续传播的CompletableFuture。f 被设置为this,继续处理当前CompletableFuture的其他Completion
情况2:返回 Completion中dep字段指向的CompletableFuture,即下一个需要处理的CompletableFuture。
postComplete通过循环而非递归来处理这个返回值
final CompletableFuture tryFire(int mode) {
// ... 执行逻辑后
return dep.postFire(src, mode); // 返回dep,即下一个CompletableFuture
}
final CompletableFuture postFire(CompletableFuture> a, int mode) {
if (a != null && a.stack != null) {
Object r;
if ((r = a.result) == null)
a.cleanStack();
// NEST == -1 不走这
if (mode >= 0 && (r != null || a.result != null))
a.postComplete();
}
if (result != null && stack != null) {
if (mode < 0)
return this;
else
postComplete();
}
return null;
}
if (f != this) {
pushStack(h);
continue;
}
这里的逻辑是:
举一个例子,用Completion结构表示:
f1.stack -> [Completion1{dep:f2}] -> [Completion2{dep:f3}] -> null
f2.stack -> [Completion3{dep:f4}] -> [Completion4{dep:f5}] -> null
f4.stack -> [Completion5{dep:f6}] -> null
postComplete执行过程
如果没有"放回去"机制,执行路径是:
f1(this)
f1 → f2 → f4 → f6
f1 → f3 (结束)
遗漏的依赖:
当f != this时(即当前处理的不是原始的f1),执行pushStack(h)将未处理的Completion放回f1的stack中。经过"放回去"机制,f1.stack动态变化:
初始:f1.stack → [Comp1{f2}] → [Comp2{f3}] → null
处理Comp1后:
f1.stack → [Comp2{f3}] → null
现在 f=f2,f2.stack → [Comp3{f4}] → [Comp4{f5}] → null
处理f2的栈时:Comp3{f4}会被放回f1.stack
最终保证所有依赖链都被正确处理。
这里是为了满足能够通过循环遍历图,如果使用递归则没必要这样处理。
虽然stack是通过CAS操作维护的链表,但这只保证了链表结构的一致性,不能保证Completion执行的唯一性。问题在于:
claim()方法使用ForkJoinTask的tag位作为原子标记:
final boolean claim() {
Executor e = executor;
if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
if (e == null)
return true;
executor = null; // disable
e.execute(this);
}
return false;
}
这里使用了ForkJoinTask的tag字段作为CAS标记,确保只有一个线程能成功claim这个Completion。
CAS操作在这里分两个层面:
例如
CompletableFuture cf1 = new CompletableFuture<>();
CompletableFuture cf2 = cf1.thenApply(String::length);
// 在不同线程中
cf1.complete("hello"); // 线程A
cf1.complete("world"); // 线程B (尝试但不会成功)
这种情况,两个线程会取执行 包含 cf2 的Completion。另一种情况是thencombine,这里有天然的多线程操作后继 Completion的操作。
stack的CAS保证了链表操作的原子性,而claim()保证了业务逻辑执行的唯一性,两者配合实现了完整的并发安全保障。
在 tryFire 方法中,关键代码是:
try {
if (mode <= 0 && !claim())
return null;
else {
@SuppressWarnings("unchecked") T t = (T) r;
d.completeValue(f.apply(t));
}
} catch (Throwable ex) {
d.completeThrowable(ex);
}
claim 在ASYNC模式没有被调用,可以通过整个链路来理解:
future.thenApplyAsync(fn)
现在我们可以清楚地理解:
tryFire(ASYNC) 的调用时机:当 Completion 被执行器异步执行时,通过 run() 或 exec() 方法调用 tryFire(ASYNC)
claim() 方法的作用:
为什么 ASYNC 模式不需要 claim:
tryFire方法有三种模式:
NESTED在postComplete中分析了
1.1 UniCompletion中的SYNC调用
在unipush方法中,当CompletableFuture已经完成时:
if (result != null)
c.tryFire(SYNC);
这种情况下,由于源CompletableFuture已经有结果,可以立即同步执行Completion。
1.2 BiCompletion中的SYNC调用
在bipush方法中,当两个源都已完成时:
final void bipush(CompletableFuture> b, BiCompletion,?,?> c) {
if (c != null) {
while (result == null) {
if (tryPushStack(c)) {
if (b.result == null)
b.unipush(new CoCompletion(c));
else if (result != null) // 检查自己有没有完成
c.tryFire(SYNC);
return;
}
}
b.unipush(c);
}
}
当都完成时,直接同步触发BiCompletion。
1.3 Or操作中的SYNC调用
在orpush方法中:
final void orpush(CompletableFuture> b, BiCompletion,?,?> c) {
if (c != null) {
while (!tryPushStack(c)) {
if (result != null) {
NEXT.set(c, null);
break;
}
}
if (result != null)
c.tryFire(SYNC);
else
b.unipush(new CoCompletion(c)); // 这里也会判断 b 有没有结束,实现了 or
}
}
final void unipush(Completion c) {
if (c != null) {
while (!tryPushStack(c)) {
if (result != null) {
NEXT.set(c, null);
break;
}
}
if (result != null)
c.tryFire(SYNC);
}
}
当任一源已完成时,立即同步执行OrCompletion。
UniCompletion中的ASYNC调用
在UniCompletion的claim方法中:
final boolean claim() {
Executor e = executor;
if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
if (e == null)
return true;
executor = null;
e.execute(this); // 这里会异步调用run()方法,最终调用tryFire(ASYNC)
}
return false;
}
当Completion需要在指定的Executor中异步执行时,会调用tryFire(ASYNC)。
Completion继承自ForkJoinTask,其exec方法:
public final boolean exec() { tryFire(ASYNC); return false; }
public final void run() { tryFire(ASYNC); }
当Completion作为ForkJoinTask执行时,会调用tryFire(ASYNC)。
以UniApply为例:
final CompletableFuture tryFire(int mode) {
// 检查前置条件
if ((a = src) == null || (r = a.result) == null
|| (d = dep) == null || (f = fn) == null)
return null;
tryComplete: if (d.result == null) {
// 处理异常结果
if (r instanceof AltResult) {
if ((x = ((AltResult)r).ex) != null) {
d.completeThrowable(x, r);
break tryComplete;
}
r = null;
}
try {
// 关键:模式判断
if (mode <= 0 && !claim())
return null;
else {
@SuppressWarnings("unchecked") T t = (T) r;
d.completeValue(f.apply(t));
}
} catch (Throwable ex) {
d.completeThrowable(ex);
}
}
// 清理引用
src = null; dep = null; fn = null;
return d.postFire(a, mode);
}
模式判断逻辑:
以BiApply为例:
final CompletableFuture tryFire(int mode) {
// 检查两个源都已完成
if ((a = src) == null || (r = a.result) == null
|| (b = snd) == null || (s = b.result) == null
|| (d = dep) == null || (f = fn) == null
|| !d.biApply(r, s, f, mode > 0 ? null : this))
return null;
// 清理引用
src = null; snd = null; dep = null; fn = null;
return d.postFire(a, b, mode);
}
在biApply方法中:
final boolean biApply(Object r, Object s,
BiFunction super R,? super S,? extends T> f,
BiApply c) {
// 处理异常...
try {
if (c != null && !c.claim()) // 当mode <= 0时,c不为null
return false;
@SuppressWarnings("unchecked") R rr = (R) r;
@SuppressWarnings("unchecked") S ss = (S) s;
completeValue(f.apply(rr, ss));
} catch (Throwable ex) {
completeThrowable(ex);
}
return true;
}
关键差异:
在前面的讨论中,我们已经了解了CompletableFuture的基本工作机制,包括uni、bi和or操作的执行流程。接下来,我将对CompletableFuture中的其他重要组件和特性进行详细分析。
Canceller
是一个实现了BiConsumer
的内部类,主要用于取消计划任务:
static final class Canceller implements BiConsumer
主要用途:用于取消超时任务。当CompletableFuture以其他方式完成时,不再需要超时触发。
工作流程:
orTimeout
或completeOnTimeout
方法),会创建一个定时任务whenComplete
注册一个Canceller使用示例:在arrangeTimeout
方法中可以看到完整流程
private void arrangeTimeout(long nanoDelay, Timeout onTimeout) {
ForkJoinPool e = ASYNC_POOL;
if (result == null) {
ScheduledForkJoinTask t = new ScheduledForkJoinTask(
nanoDelay, 0L, true, onTimeout, null, e);
whenComplete(new Canceller(t)); // 注册Canceller取消器
e.scheduleDelayedTask(t);
}
}
Timeout
是一个实现了Runnable
的内部类,负责在超时发生时执行操作:
static final class Timeout implements Runnable {
final CompletableFuture f;
final U value;
final boolean exceptional;
Timeout(CompletableFuture f, U value, boolean exceptional) {
this.f = f; this.value = value; this.exceptional = exceptional;
}
public void run() {
if (f != null && !f.isDone()) {
if (exceptional)
f.completeExceptionally(new TimeoutException());
else
f.complete(value);
}
}
}
Timeout的工作机制
两种工作模式:
exceptional=true
):超时时以TimeoutException
异常完成Futureexceptional=false
):超时时以指定的默认值完成Future对应的公共API:
orTimeout(timeout, unit)
:超时抛异常completeOnTimeout(value, timeout, unit)
:超时使用默认值执行流程:
Signaller
是一个特殊的Completion
子类,实现了ForkJoinPool.ManagedBlocker
接口,用于支持阻塞等待操作:
设计:
ManagedBlocker
接口,确保在ForkJoinPool中阻塞时不会导致线程饥饿等待过程:
LockSupport.park
或LockSupport.parkNanos
挂起线程tryFire
方法唤醒等待线程唤醒机制:
postComplete
处理栈中的依赖tryFire
方法会解除线程的阻塞状态 static final class Signaller extends Completion
implements ForkJoinPool.ManagedBlocker {
long nanos; // remaining wait time if timed
final long deadline; // non-zero if timed
final boolean interruptible;
boolean interrupted;
volatile Thread thread;
Signaller(boolean interruptible, long nanos, long deadline) {
this.thread = Thread.currentThread();
this.interruptible = interruptible;
this.nanos = nanos;
this.deadline = deadline;
}
final CompletableFuture> tryFire(int ignore) {
Thread w; // no need to atomically claim
if ((w = thread) != null) {
thread = null;
LockSupport.unpark(w);
}
return null;
}
public boolean isReleasable() {
if (Thread.interrupted())
interrupted = true;
return ((interrupted && interruptible) ||
(deadline != 0L &&
(nanos <= 0L ||
(nanos = deadline - System.nanoTime()) <= 0L)) ||
thread == null);
}
public boolean block() {
while (!isReleasable()) {
if (deadline == 0L)
LockSupport.park(this);
else
LockSupport.parkNanos(this, nanos);
}
return true;
}
final boolean isLive() { return thread != null; }
}
anyOf
静态方法创建一个在任何输入CompletableFuture完成时完成的新CompletableFuture:
核心类:AnyOf
Completion类
设计特点:
执行流程:
优化处理:
public static CompletableFuture
边界条件处理:
快速完成检查:
注册依赖:
清理:
AnyOf Completion类:
static class AnyOf extends Completion {
CompletableFuture dep; CompletableFuture> src;
CompletableFuture>[] srcs;
AnyOf(CompletableFuture dep, CompletableFuture> src,
CompletableFuture>[] srcs) {
this.dep = dep; this.src = src; this.srcs = srcs;
}
final CompletableFuture tryFire(int mode) {
// assert mode != ASYNC;
CompletableFuture d; CompletableFuture> a;
CompletableFuture>[] as;
Object r;
if ((a = src) == null || (r = a.result) == null
|| (d = dep) == null || (as = srcs) == null)
return null;
src = null; dep = null; srcs = null;
if (d.completeRelay(r)) {
for (CompletableFuture> b : as)
if (b != a)
b.cleanStack();
if (mode < 0)
return d;
else
d.postComplete();
}
return null;
}
final boolean isLive() {
CompletableFuture d;
return (d = dep) != null && d.result == null;
}
}
tryFire
方法在源CompletableFuture完成时被调用allOf
静态方法创建一个在所有输入CompletableFuture完成时完成的新CompletableFuture:
核心方法:andTree
- 递归构建完成树
设计特点:
执行流程:
优化处理:
BiRelay是一个特殊的BiCompletion,用于协调两个输入CompletableFuture,只有当两者都完成时才完成依赖的Future。
public static CompletableFuture allOf(CompletableFuture>... cfs) {
return andTree(cfs, 0, cfs.length - 1);
}
allOf实际上是调用了andTree
方法:
static CompletableFuture andTree(CompletableFuture>[] cfs,
int lo, int hi) {
CompletableFuture d = new CompletableFuture();
if (lo > hi) // empty
d.result = NIL;
else {
CompletableFuture> a, b; Object r, s, z; Throwable x;
int mid = (lo + hi) >>> 1;
if ((a = (lo == mid ? cfs[lo] :
andTree(cfs, lo, mid))) == null ||
(b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] :
andTree(cfs, mid+1, hi))) == null)
throw new NullPointerException();
if ((r = a.result) == null || (s = b.result) == null)
a.bipush(b, new BiRelay<>(d, a, b));
else if ((r instanceof AltResult
&& (x = ((AltResult)(z = r)).ex) != null) ||
(s instanceof AltResult
&& (x = ((AltResult)(z = s)).ex) != null))
d.result = encodeThrowable(x, z);
else
d.result = NIL;
}
return d;
}
allOf实现详解:
构建二叉树:
处理边界条件:
递归构建子树:
状态检查和依赖设置:
BiRelay类:
static final class BiRelay extends BiCompletion {
BiRelay(CompletableFuture dep,
CompletableFuture src, CompletableFuture snd) {
super(null, dep, src, snd);
}
final CompletableFuture tryFire(int mode) {
CompletableFuture d;
CompletableFuture a;
CompletableFuture b;
Object r, s, z; Throwable x;
if ( (a = src) == null || (r = a.result) == null
|| (b = snd) == null || (s = b.result) == null
|| (d = dep) == null)
return null;
if (d.result == null) {
if ((r instanceof AltResult
&& (x = ((AltResult)(z = r)).ex) != null) ||
(s instanceof AltResult
&& (x = ((AltResult)(z = s)).ex) != null))
d.completeThrowable(x, z);
else
d.completeNull();
}
src = null; snd = null; dep = null;
return d.postFire(a, b, mode);
}
}
encodeRelay
主要用于以下场景:
encodeRelay
确保异常结果被正确包装为CompletionException
,从而保持CompletableFuture的异常处理一致性。假设有两个CompletableFuture f1
和f2
,f2
依赖于f1
的结果:
CompletableFuture f1 = CompletableFuture.supplyAsync(() -> {
throw new RuntimeException("Error in f1");
});
CompletableFuture f2 = f1.thenApply(result -> {
// Do something with result
return result * 2;
});
在这种情况下,如果f1
异常完成,f2
需要正确处理该异常。encodeRelay
确保f1
的异常结果被传递给f2
时,被正确包装为CompletionException
。
completeRelay 则设置这个包装结果
final boolean completeRelay(Object r) {
return RESULT.compareAndSet(this, null, encodeRelay(r));
}
// 5秒后超时并抛出异常
CompletableFuture future = someAsyncOperation()
.orTimeout(5, TimeUnit.SECONDS);
// 5秒后超时并返回默认值
CompletableFuture future = someAsyncOperation()
.completeOnTimeout("Default value", 5, TimeUnit.SECONDS);
工作流程:
String result = future.get(); // 可能阻塞直到完成
String result = future.get(10, TimeUnit.SECONDS); // 带超时的阻塞
工作流程:
// 等待所有Future完成
CompletableFuture allDone = CompletableFuture.allOf(future1, future2, future3);
// 等待任一Future完成
CompletableFuture anyDone = CompletableFuture.anyOf(future1, future2, future3);
工作流程(allOf):
工作流程(anyOf):
CompletableFuture的这些高级特性体现了其强大的异步编程能力:
这些机制共同构建了CompletableFuture强大且灵活的异步编程模型,使其成为Java中处理复杂异步流程的核心工具。
CompletableFuture 提供了几种获取计算结果的方法:get()
、get(timeout, unit)
、join()
和getNow()
。这些方法的内部实现都涉及 waitingGet
、timedGet
、reportGet
和 reportJoin
等私有方法。下面详细分析它们的执行流程。
get()
方法的执行流程当外部使用者调用 CompletableFuture.get()
方法时:
public T get() throws InterruptedException, ExecutionException {
Object r;
if ((r = result) == null)
r = waitingGet(true);
return (T) reportGet(r, "get");
}
执行步骤:
result
字段是否为 nullresult
不为 null,表示任务已完成,直接获取结果result
为 null,调用 waitingGet(true)
等待任务完成reportGet
方法处理结果并返回waitingGet
方法分析waitingGet
方法实现了阻塞等待任务完成的核心逻辑:
private Object waitingGet(boolean interruptible) {
if (interruptible && Thread.interrupted())
return null;
Signaller q = null;
boolean queued = false;
Object r;
while ((r = result) == null) {
if (q == null) {
q = new Signaller(interruptible, 0L, 0L);
if (Thread.currentThread() instanceof ForkJoinWorkerThread)
ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
}
else if (!queued)
queued = tryPushStack(q);
else if (interruptible && q.interrupted) {
q.thread = null;
cleanStack();
return null;
}
else {
try {
ForkJoinPool.managedBlock(q);
} catch (InterruptedException ie) {
q.interrupted = true;
}
}
}
if (q != null) {
q.thread = null;
if (q.interrupted)
Thread.currentThread().interrupt();
}
postComplete();
return r;
}
执行步骤:
interruptible
为 true)Signaller
实例作为等待节点ForkJoinWorkerThread
,尝试帮助处理异步阻塞任务Signaller
节点推入等待栈中ForkJoinPool.managedBlock(q)
阻塞当前线程result
不为 null),处理中断状态并调用 postComplete()
最后一段代码的目的是保留中断状态:
Signaller
类的作用Signaller
是 CompletableFuture
中实现线程等待和唤醒机制的关键类:
Signaller
同时扩展了 Completion
和实现了 ForkJoinPool.ManagedBlocker
接口CompletableFuture
的等待栈中CompletableFuture
完成时,会调用 tryFire()
方法唤醒等待的线程isReleasable()
判断是否可以结束阻塞状态block()
实现了线程的阻塞逻辑,使用 LockSupport.park/parkNanos
get(timeout, unit)
和 timedGet
方法带超时参数的 get
方法:
public T get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
long nanos = unit.toNanos(timeout);
Object r;
if ((r = result) == null)
r = timedGet(nanos);
return (T) reportGet(r, "get");
}
timedGet
方法与 waitingGet
类似,但增加了超时处理:
private Object timedGet(long nanos) throws TimeoutException {
long d = System.nanoTime() + nanos;
long deadline = (d == 0L) ? 1L : d; // 避免为0
boolean interrupted = false, queued = false;
Signaller q = null;
Object r = null;
for (;;) { // 检查中断、结果、超时的顺序很重要
if (interrupted || (interrupted = Thread.interrupted()))
break;
else if ((r = result) != null)
break;
else if (nanos <= 0L)
break;
else if (q == null) {
q = new Signaller(true, nanos, deadline);
if (Thread.currentThread() instanceof ForkJoinWorkerThread)
ForkJoinPool.helpAsyncBlocker(defaultExecutor(), q);
}
else if (!queued)
queued = tryPushStack(q);
else {
try {
ForkJoinPool.managedBlock(q);
interrupted = q.interrupted;
nanos = q.nanos;
} catch (InterruptedException ie) {
interrupted = true;
}
}
}
// 清理和恢复
if (q != null) {
q.thread = null;
if (r == null)
cleanStack();
}
// 根据不同情况返回结果或抛出异常
if (r != null) {
if (interrupted)
Thread.currentThread().interrupt();
postComplete();
return r;
} else if (interrupted)
return null;
else
throw new TimeoutException();
}
与 waitingGet
相比,timedGet
增加了:
Signaller
TimeoutException
reportGet
和 reportJoin
方法这两个方法处理结果并根据不同情况抛出异常:
private static Object reportGet(Object r, String details)
throws InterruptedException, ExecutionException {
if (r == null) // 按约定,null表示中断
throw new InterruptedException();
if (r instanceof AltResult) {
Throwable x, cause;
if ((x = ((AltResult)r).ex) == null)
return null;
if (x instanceof CancellationException)
throw new CancellationException(details, (CancellationException)x);
if ((x instanceof CompletionException) &&
(cause = x.getCause()) != null)
x = cause;
throw wrapInExecutionException(x);
}
return r;
}
private static Object reportJoin(Object r, String details) {
if (r instanceof AltResult) {
Throwable x;
if ((x = ((AltResult)r).ex) == null)
return null;
if (x instanceof CancellationException)
throw new CancellationException(details, (CancellationException)x);
if (x instanceof CompletionException)
throw (CompletionException)x;
throw wrapInCompletionException(x);
}
return r;
}
关键区别:
reportGet
抛出受检异常 ExecutionException
,用于 get()
方法reportJoin
抛出非受检异常 CompletionException
,用于 join()
和 getNow()
方法null
值的处理不同join()
和 getNow()
方法public T join() {
Object r;
if ((r = result) == null)
r = waitingGet(false);
return (T) reportJoin(r, "join");
}
public T getNow(T valueIfAbsent) {
Object r;
return ((r = result) == null) ? valueIfAbsent : (T) reportJoin(r, "getNow");
}
join()
类似于 get()
,但使用 waitingGet(false)
表示不可中断,并使用 reportJoin
getNow()
不会等待,如果结果不可用则返回指定的默认值get()/join()/getNow()
方法获取结果result
字段是否为 nullwaitingGet
或 timedGet
进入等待状态Signaller
对象并添加到等待栈中ForkJoinPool.managedBlock
或直接 LockSupport.park
阻塞postComplete()
唤醒等待的线程reportGet
或 reportJoin
处理结果