FutureTask 是 JDK 1.7 前 Future 唯一實現,JDK 8 仍廣泛用於線程池任務提交。本文基於源碼剖析其 7 狀態機、run() 執行流程、get() 阻塞喚醒、cancel() 取消語義及爭議行為。
cancel(boolean mayInterruptIfRunning):嘗試取消任務isCancelled() / isDone():狀態查詢get() / get(timeout, unit):阻塞獲取結果或異常FutureTask implements RunnableFuture
RunnableFuture extends Runnable, Future
即可作為 Runnable 提交執行,也可作為 Future 獲取結果。
| 狀態常量 | 值 | 含義 |
|---|---|---|
| NEW | 0 | 初始狀態,構造函數設置 |
| COMPLETING | 1 | 任務即將完成(正常或異常) |
| NORMAL | 2 | 正常完成,結果保存在 outcome |
| EXCEPTIONAL | 3 | 異常完成,異常對象保存在 outcome |
| CANCELLED | 4 | 取消完成(mayInterruptIfRunning=false) |
| INTERRUPTING | 5 | 正在中斷執行線程 |
| INTERRUPTED | 6 | 中斷完成(mayInterruptIfRunning=true) |
狀態流轉路徑:
NEW → COMPLETING → NORMALNEW → COMPLETING → EXCEPTIONALNEW → CANCELLEDNEW → INTERRUPTING → INTERRUPTEDpublic void run() {
if (state != NEW || !UNSAFE.compareAndSwapObject(this, runnerOffset, null, Thread.currentThread()))
return; // 狀態非 NEW 或 runner 已被設置,直接返回
try {
Callable c = callable;
if (c != null && state == NEW) {
V result; boolean ran = false;
try {
result = c.call(); // 執行用戶任務
ran = true;
} catch (Throwable ex) {
result = null;
setException(ex); // 異常路徑:state → COMPLETING → EXCEPTIONAL
}
if (ran) set(result); // 正常路徑:state → COMPLETING → NORMAL
}
} finally {
runner = null; // 清除 runner 引用
int s = state;
if (s >= INTERRUPTING) handlePossibleCancellationInterrupt(s); // 處理取消中斷殘留
}
}
關鍵點:
runner 確保單次執行set(V)/setException(Throwable) 內部 CAS 更新狀態,寫入 outcome,最後 finishCompletion() 喚醒等待線程outcome 字段雙重用途:正常時存結果,異常時存異常對象public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING) s = awaitDone(false, 0L); // 狀態未終態,進入阻塞等待
return report(s);
}
private V report(int s) throws ExecutionException {
Object x = outcome;
if (s == NORMAL) return (V) x;
if (s >= CANCELLED) throw new CancellationException();
throw new ExecutionException((Throwable) x);
}
awaitDone 內部使用 LockSupport.park/parkNanos 掛起線程,任務完成時 finishCompletion() 調用 LockSupport.unpark 喚醒。超時版本 get(timeout, unit) 同理,超時拋 TimeoutException。
public boolean cancel(boolean mayInterruptIfRunning) {
if (state != NEW) return false; // 非 NEW 狀態不可取消
if (mayInterruptIfRunning) {
if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, INTERRUPTING)) return false;
Thread t = runner;
if (t != null) t.interrupt(); // 僅設置中斷標誌!
UNSAFE.putOrderedInt(this, stateOffset, INTERRUPTED);
} else if (!UNSAFE.compareAndSwapInt(this, stateOffset, NEW, CANCELLED)) return false;
finishCompletion();
return true;
}
提交耗時 1s 的任務,立即調用 cancel(false),兩種輸出:
cancel 返回 true,任務從未運行cancel 返回 true,但任務繼續跑完(打印 "當前任務執行已經超過1s")原因:cancel(false) 僅修改狀態為 CANCELLED,不中斷執行線程。線程繼續運行直到正常返回或異常,但 FutureTask 狀態已終態,後續 get() 拋 CancellationException。
調用 runner.interrupt() 設置中斷標誌。僅當任務代碼響應中斷(拋 InterruptedException、檢查 interrupted())時才能真正停止。若任務為死循環 CPU 計算,中斷無效。
get() 通過 LockSupport 高效阻塞/喚醒cancel() 不保證任務停止:false 僅改狀態,true 僅發中斷信號Thread.interrupted()、拋 InterruptedException)Future、排查任務「取消不生效」、異常吞沒等問題