FutureTask 實現了 Future 和 Runnable,是「異步計算+結果獲取」的核心工具。本文通過預加載場景演示其核心用法,並延伸超時、取消、異常處理最佳實踐。
public class DataPreloader {
private final FutureTask<List<String>> future = new FutureTask<>(() -> {
Thread.sleep(10000); // 模擬耗時加載
return IntStream.range(0, 10).mapToObj(i -> "data" + i).collect(Collectors.toList());
});
private final Thread loaderThread = new Thread(future, "DataPreloader");
public void start() { loaderThread.start(); }
public List<String> getData() throws InterruptedException, ExecutionException {
return future.get(); // 計算完成直接返回,否則阻塞等待
}
public List<String> getData(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return future.get(timeout, unit); // 支援超時控制
}
public boolean cancel(boolean mayInterrupt) { return future.cancel(mayInterrupt); }
public boolean isDone() { return future.isDone(); }
}
| 方法 | 說明 |
|---|---|
| get() | 阻塞直到完成,返回結果或拋出 ExecutionException |
| get(timeout, unit) | 超時拋出 TimeoutException,不阻塞無限期 |
| cancel(true) | 嘗試中斷執行中的任務(需任務響應 interrupt) |
| isDone() | 非阻塞檢查是否完成(含正常/異常/取消) |
| run() | 實現 Runnable,可直接提交給 Executor |
get() 只計算一次。ConcurrentHashMap<Key, FutureTask<Value>> 實現「相同 Key 只加載一次」模式。CompletableFuture.supplyAsync() 替代,支援鏈式回調、組合、異常處理更強。Thread.interrupt(),否則 cancel(true) 無效。get() 會拋出 ExecutionException 包裝真實異常,需 getCause() 獲取根因。get(),導致界面凍結。FutureTask 是「畂步計算句柄」的標準實現,適用於「提前觸發、稍後獲取」場景。現代代碼優先選 CompletableFuture,但理解 FutureTask 原理對掌握 JDK 併發包基石至關重要。