前面兩篇文章簡單列舉了Java 多線程的一些實際場景,但是這兩個例子還是過于淺顯,僅僅能應對面試官的提問。在后續(xù)文章中我們會基于更實戰(zhàn)一些的案例來討論下并發(fā)編程。本篇文章使用了大模型進行偽代碼和一些特性枚舉的生成,本人基于大模型生成的內(nèi)容做了內(nèi)容核實和校準,可以放心閱讀。
一、引言
在 Java 的并發(fā)編程中,我們經(jīng)常需要在子線程中執(zhí)行任務并異步獲取結(jié)果。
早期可以通過 Thread 或 Runnable 來實現(xiàn)并發(fā)執(zhí)行,但它們的缺點是:
- 無法方便地獲取任務執(zhí)行結(jié)果;
- 無法優(yōu)雅地處理任務取消、異常、狀態(tài)管理等。
為了解決這些問題,JDK 1.5 引入了 Future 接口和 FutureTask 類,為異步任務提供了一種標準化的管理方式。
二、Future 與 FutureTask 簡介
1. Future 接口
Future<V> 表示一個異步計算的結(jié)果,它提供了幾個核心方法:
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
這些方法允許我們:
? 取消任務(cancel)
? 檢查任務狀態(tài)(isDone、isCancelled)
? 阻塞等待結(jié)果(get)
- FutureTask 類
FutureTask 是 Future 接口的一個實現(xiàn)類,同時還實現(xiàn)了 Runnable 接口。
也就是說:
一個 FutureTask 既是一個任務(可以被線程或線程池執(zhí)行),也是一個可獲取結(jié)果的 Future。
其核心類聲明如下:
public class FutureTask<V> implements RunnableFuture<V> {
// RunnableFuture 繼承了 Runnable 和 Future
}
因此,F(xiàn)utureTask 既能提交給 Thread 執(zhí)行,也能提交給 ExecutorService 管理。
三、FutureTask 的內(nèi)部原理
FutureTask 內(nèi)部是通過 狀態(tài)機 + CAS + LockSupport 實現(xiàn)的異步結(jié)果控制。
- 狀態(tài)控制
FutureTask 內(nèi)部有一個 volatile int state 變量,用于標識任務狀態(tài):
| 狀態(tài)名 | 含義 |
|---|---|
| NEW | 初始狀態(tài),任務未開始 |
| COMPLETING | 正在設置結(jié)果 |
| NORMAL | 執(zhí)行成功 |
| EXCEPTIONAL | 執(zhí)行拋出異常 |
| CANCELLED | 已取消(未執(zhí)行) |
| INTERRUPTING | 正在中斷執(zhí)行 |
| INTERRUPTED | 已中斷執(zhí)行完畢 |
任務狀態(tài)通過 CAS 操作原子更新,保證線程安全。
?
- 執(zhí)行流程
當調(diào)用 FutureTask.run() 時,主要流程如下:
public void run() {
if (state != NEW || !runner.compareAndSet(null, Thread.currentThread()))
return; // 已執(zhí)行或其他線程執(zhí)行中
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result = c.call(); // 執(zhí)行任務
set(result); // 設置結(jié)果
}
} catch (Throwable ex) {
setException(ex); // 設置異常
}
}
核心點:
? 任務執(zhí)行邏輯由 Callable.call() 實現(xiàn);
? 執(zhí)行完成后通過 set(result) 設置結(jié)果并喚醒等待的線程;
? 如果拋出異常,則調(diào)用 setException(ex)。
- 結(jié)果等待機制
當主線程調(diào)用 get() 時,如果結(jié)果未完成,會進入等待狀態(tài):
public V get() throws InterruptedException, ExecutionException {
int s = state;
if (s <= COMPLETING)
s = awaitDone(false, 0L); // 阻塞等待
return report(s); // 返回結(jié)果或拋異常
}
底層使用 LockSupport.park() 讓線程阻塞,直到任務完成時調(diào)用 LockSupport.unpark() 喚醒。
四、FutureTask 的使用示例
示例一:直接用 Thread 執(zhí)行 FutureTask
import java.util.concurrent.*;
public class FutureTaskDemo1 {
public static void main(String[] args) throws Exception {
Callable<Integer> callable = () -> {
System.out.println("計算中...");
Thread.sleep(2000);
return 42;
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
Thread thread = new Thread(futureTask);
thread.start();
System.out.println("主線程執(zhí)行其他任務...");
System.out.println("結(jié)果: " + futureTask.get());
}
}
輸出:
主線程執(zhí)行其他任務...
計算中...
結(jié)果: 42
示例二:結(jié)合線程池使用
import java.util.concurrent.*;
public class FutureTaskDemo2 {
public static void main(String[] args) throws Exception {
ExecutorService executor = Executors.newFixedThreadPool(2);
FutureTask<String> futureTask = new FutureTask<>(() -> {
Thread.sleep(1000);
return "任務完成";
});
executor.submit(futureTask);
// 等待結(jié)果
System.out.println(futureTask.get());
executor.shutdown();
}
}
示例三:任務取消與狀態(tài)判斷
FutureTask<Integer> future = new FutureTask<>(() -> {
Thread.sleep(3000);
return 10;
});
new Thread(future).start();
Thread.sleep(1000);
boolean cancelled = future.cancel(true); // 嘗試取消
System.out.println("是否取消成功:" + cancelled);
System.out.println("任務是否完成:" + future.isDone());
五、FutureTask 與 CompletableFuture 的關(guān)系
自 Java 8 起,CompletableFuture 進一步增強了 FutureTask 的能力,支持:
? 鏈式回調(diào) (thenApply, thenAccept)
? 異步組合 (thenCombine, allOf)
? 非阻塞結(jié)果獲取
可以認為:
FutureTask 是基礎(chǔ)設施級的 Future 實現(xiàn),而 CompletableFuture 是它的進化版本。
六、總結(jié)
| 特性 | FutureTask |
|---|---|
| 核心接口 | 實現(xiàn) RunnableFuture(= Runnable + Future) |
| 功能 | 異步執(zhí)行、結(jié)果獲取、取消、狀態(tài)控制 |
| 內(nèi)部機制 | CAS 狀態(tài)機 + LockSupport |
| 使用方式 | 可直接 new Thread(futureTask).start() 或提交給線程池 |
| 適用場景 | 需要精細控制任務生命周期的異步操作 |