傳統 Thread 與 Runnable 無法直接獲取執行結果。若有多個線程並行計算,最終需匯總結果(如 Thread1~3 統計數據,Thread4 匯總),Callable + Future 是標準解法。
| 介面 | 方法簽名 | 返回值 | 拋出異常 |
|---|---|---|---|
| Runnable | void run() | 無 | 不可拋受檢異常 |
| Callable<V> | V call() | 泛型 V | 可拋 Exception |
get() 阻塞獲取結果、cancel() 取消任務、isDone() 判斷完成狀態RunnableFuture<V>,同時是 Runnable(可提交執行緒池)與 Future(可獲取結果)public class GreyStartServlet extends HttpServlet {
@Override
public void init() throws ServletException {
// 包裝 Callable 為 FutureTask
FutureTask<String> task = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
start(); // 耗時操作
return "Collection Completed";
}
});
// 提交給新執行緒執行,不阻塞 Tomcat 啟動
new Thread(task).start();
}
private static void start() throws Exception {
Thread.sleep(1000); // 模擬耗時初始化
}
}
ExecutorService executor = Executors.newFixedThreadPool(3);
List<Future<Integer>> futures = new ArrayList<>();
for (int i = 0; i < 3; i++) {
final int taskId = i;
Future<Integer> future = executor.submit(new Callable<Integer>() {
@Override
public Integer call() throws Exception {
// 模擬統計邏輯
Thread.sleep(500);
return taskId * 100;
}
});
futures.add(future);
}
// 主線程匯總結果
int total = 0;
for (Future<Integer> f : futures) {
total += f.get(); // 阻塞直到結果就緒
}
System.out.println("總計:" + total);
executor.shutdown();
Future.get() 會阻塞當前線程,建議設定超時:get(5, TimeUnit.SECONDS)call() 拋出的異常會被包裝在 ExecutionException 中,get() 時重拋future.cancel(true) 嘗試中斷正在執行的任務FutureTask 可重複提交嗎?不可,執行完成後狀態固定,需新建實例