相較於 Runnable 無法回傳值且無法拋出受檢異常,Callable<V> 介面支援泛型回傳值與異常傳播。配合 FutureTask 與執行緒池,可實現真正的非同步運算與結果獲取。本文完整解析核心 API 與實戰模式。
call() 回傳 V 型別結果get()、cancel()、isDone() 等方法submit() 提交 Callable/FutureTaskpackage com.future.test;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
/**
* Callable 與 FutureTask 綜合示範
*/
public class CallableFutureDemo {
public static void main(String[] args) {
// 建立單一執行緒執行緒池
ExecutorService executor = Executors.newSingleThreadExecutor();
// 建立 FutureTask 包裝 Callable 任務
FutureTask futureTask = new FutureTask<>(new Callable() {
@Override
public String call() throws Exception {
// 模擬耗時運算(10 秒)
System.out.println("【任務開始】執行耗時運算...");
Thread.sleep(10_000);
System.out.println("【任務完成】運算結束");
return "運算結果:11111";
}
});
// 提交任務至執行緒池(非阻塞)
executor.execute(futureTask);
System.out.println("【主執行緒】任務已提交,繼續處理其他業務...");
// 主執行緒可繼續做其他工作
doOtherWork();
// 獲取結果(支援超時控制)
String result = null;
try {
// 等待最多 5 秒,超時拋出 TimeoutException
result = futureTask.get(5, TimeUnit.SECONDS);
System.out.println("【結果獲取】成功:" + result);
} catch (TimeoutException e) {
System.err.println("【超時】任務執行超過 5 秒,取消任務");
futureTask.cancel(true); // true 表示中斷正在執行的任務
} catch (InterruptedException e) {
System.err.println("【中斷】主執行緒被中斷");
futureTask.cancel(true);
} catch (ExecutionException e) {
System.err.println("【異常】任務執行拋出異常:" + e.getCause().getMessage());
futureTask.cancel(true);
} finally {
// 關閉執行緒池
executor.shutdown();
System.out.println("【執行緒池】已關閉");
}
System.out.println("最終結果:" + result);
}
private static void doOtherWork() {
// 模擬主執行緒處理其他業務
for (int i = 1; i <= 3; i++) {
System.out.println("【主執行緒】處理其他業務 " + i);
try { Thread.sleep(1000); } catch (InterruptedException ignored) {}
}
}
}
executor.execute(futureTask) 非阻塞提交,主執行緒立即繼續doOtherWork(),工作執行緒執行 call()futureTask.get(5, TimeUnit.SECONDS) 阻塞等待,支援超時finally 區塊確保執行緒池關閉List> tasks = new ArrayList<>();
for (int i = 0; i < 10; i++) {
final int taskId = i;
FutureTask task = new FutureTask<>(() -> {
Thread.sleep(1000);
return taskId * 2;
});
tasks.add(task);
executor.execute(task);
}
// 收集所有結果
for (FutureTask task : tasks) {
try {
System.out.println("任務結果:" + task.get());
} catch (Exception e) {
e.printStackTrace();
}
}
List> callables = Arrays.asList(
() -> { Thread.sleep(1000); return "任務A"; },
() -> { Thread.sleep(2000); return "任務B"; }
);
List> futures = executor.invokeAll(callables);
for (Future f : futures) {
System.out.println(f.get());
}
| 問題 | 解決方案 |
|---|---|
| get() 無限阻塞 | 永遠使用帶超時的 get(timeout, unit) |
| 異常吞沒 | ExecutionException 需呼叫 getCause() 取得真實異常 |
| 執行緒池洩漏 | 必須在 finally 區塊呼叫 shutdown() 或 shutdownNow() |
| 取消任務無效 | cancel(true) 需任務內部定期檢查 Thread.interrupted() |
Java 8 引入 CompletableFuture 提供更豐富的非同步組合 API(thenApply、thenCompose、allOf 等),新專案建議優先使用:
CompletableFuture.supplyAsync(() -> {
Thread.sleep(1000);
return "非同步結果";
}).thenAccept(result -> System.out.println(result));