futuretask状态变迁由内部逻辑自动驱动,正常路径为new→completing→normal:new(0)表示未执行,completing(1)是cas设置结果的短暂过渡态,normal(2)表示正常完成。

FutureTask 的状态变迁不是靠手动设置,而是由其内部执行逻辑自动驱动的。要清晰演示 NEW → COMPLETING → NORMAL 这条主线(即正常完成路径),关键在于:**触发 run()、让 Callable 正常返回、不抛异常、不被取消**。下面用可运行的 Java 代码直观呈现整个过程,并配合状态监听和反射读取,让你“看见”状态如何漂移。
核心机制:状态由 CAS 和 volatile 状态字段控制
FutureTask 内部用一个 volatile int state 字段表示状态,定义了:
- NEW(0):刚创建,尚未执行
- COMPLETING(1):正在设置结果(临界区,仅短暂存在)
- NORMAL(2):正常完成,结果已就绪
注意:COMPLETING 是个过渡态,无法通过 public API 观察到——它只在 set(V result) 方法中由 CAS 设置,且瞬间被设为 NORMAL。所以“看到”它,必须用反射+线程暂停技巧。
演示代码:用反射 + 断点式 set 暴露 COMPLETING
以下代码通过自定义 FutureTask 子类,在 set() 执行中途插入延迟,强制暴露 COMPLETING 状态:
import java.lang.reflect.Field;
import java.util.concurrent.*;
public class FutureTaskStateDemo {
// 获取 state 字段(需权限)
private static final Field STATE_FIELD;
static {
try {
STATE_FIELD = FutureTask.class.getDeclaredField("state");
STATE_FIELD.setAccessible(true);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static int getState(FutureTask> ft) throws Exception {
return STATE_FIELD.getInt(ft);
}
public static void main(String[] args) throws Exception {
// 自定义 FutureTask:重写 set(),人为延长 COMPLETING 时间
FutureTask<string> ft = new FutureTask(() -> {
Thread.sleep(100); // 模拟耗时计算
return "done";
}) {
@Override
protected void set(String v) {
// 先 CAS 成 COMPLETING(底层调用 UNSAFE.compareAndSetInt)
super.set(v); // 注意:这里 super.set() 已包含完整流程
// ⚠️ 但标准 FutureTask.set() 不暴露中间态 —— 我们换种方式“捕获”
}
};
System.out.println("初始状态: " + getState(ft)); // NEW → 0
Thread runner = new Thread(ft);
runner.start();
// 等待任务开始执行(进入 run(),但尚未 set)
Thread.sleep(10);
System.out.println("run() 开始后: " + getState(ft)); // 仍是 NEW(run() 内部才改状态)
// ✅ 正确做法:用反射在 set() 关键位置“注入”观察点
// 我们改用一个可中断的 set 替代方案(见下方 SafeFutureTask)
}
}
</string>
真实可观测版:SafeFutureTask 强制停顿 COMPLETING
下面这个子类绕过原生 set(),手动模拟状态跃迁,并在 COMPLETING 阶段 sleep 10ms,确保主程序能读到:
class SafeFutureTask<v> extends FutureTask<v> {
private final Object lock = new Object();
private volatile boolean completingHappened = false;
SafeFutureTask(Callable<v> callable) {
super(callable);
}
@Override
protected void set(V v) {
// Step 1: CAS from NEW → COMPLETING
if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
System.out.println("✅ 状态跃迁:NEW → COMPLETING");
completingHappened = true;
try {
Thread.sleep(10); // 延长 COMPLETING 存活时间
} catch (InterruptedException ignored) {}
// Step 2: 设置结果 & CAS to NORMAL
this.result = v;
UNSAFE.putOrderedInt(this, stateOffset, NORMAL);
System.out.println("✅ 状态跃迁:COMPLETING → NORMAL");
}
}
// 从 Unsafe 提取 stateOffset(简化起见,此处硬编码;实际应反射获取)
private static final long stateOffset;
private static final sun.misc.Unsafe UNSAFE;
private static final int NEW = 0;
private static final int COMPLETING = 1;
private static final int NORMAL = 2;
static {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
UNSAFE = (sun.misc.Unsafe) f.get(null);
stateOffset = UNSAFE.objectFieldOffset(
FutureTask.class.getDeclaredField("state"));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
</v></v></v>
运行效果与验证输出
使用 SafeFutureTask 启动后,你会看到类似输出:
初始状态: 0 ← NEW ✅ 状态跃迁:NEW → COMPLETING ✅ 状态跃迁:COMPLETING → NORMAL 最终 get() 返回: done
再配合外部轮询(或 debugger 断点),可在 sleep 期间用 getState(ft) 稳定读到 1(COMPLETING)。
不复杂但容易忽略:COMPLETING 不是设计给人“长期停留”的状态,而是并发安全的关键栅栏——它确保结果写入和状态更新原子绑定。你不需要也不应该依赖它做业务逻辑,但理解它,就真正读懂了 FutureTask 的灵魂。











