| 方法 | 返回值 | 異常處理 | 適用場景 |
execute(Runnable) | void | 拋出到 Thread.UncaughtExceptionHandler | 無需結果、火鑿忘型任務 |
submit(Runnable) | Future<?> (get() 返回 null) | 異常包裹在 Future.get() 拋出 ExecutionException | 需狀態確認、異常捕獲 |
submit(Callable<T>) | Future<T> | 同上 | 需返回結果 |
Future.get() 阻塞陷阱
Future<String> f = executor.submit(task);
try {
String result = f.get(3, TimeUnit.SECONDS); // 超時控制,避免無限阻塞
} catch (TimeoutException e) {
f.cancel(true); // 中斷任務釋放資源
}
CompletionService:異步結果「誰先完成誰先拿」
痛點:提交 10 個任務,需 10 個 Future 逐個 get(),順序固定,早完成的也要等晚完成的。
方案:ExecutorCompletionService = Executor + BlockingQueue<Future>。
核心用法
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletionService<String> cs = new ExecutorCompletionService<>(executor);
// 提交 10 個任務
for (int i = 0; i < 10; i++) {
cs.submit(() -> {
Thread.sleep(new Random().nextInt(1000));
return Thread.currentThread().getName() + " done";
});
}
// 完成順序獲取結果(非提交順序)
for (int i = 0; i < 10; i++) {
try {
String result = cs.take().get(); // 取出已完成任務的 Future,再 get()
System.out.println(result);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
executor.shutdown();
原理解析
- 提交時包裝為
QueueingFuture(繼承 FutureTask),重寫 done() 將結果放入內部 completionQueue。
take() 阻塞等待隊列有元素;poll(timeout) 支持超時。
- 實現「生產者提交、消費者按完成序消費」模式,極大簡化異步編排。
總結與最佳實踐
- 拒絕 Executors 默認工廠,顯式構造
ThreadPoolExecutor,參數有據可依。
- 業務隔離:不同業務類型(CPU/IO、核心/非核心)使用獨立線程池,避免相互擠佔。
- 命名規範:
ThreadFactory 設置有意義前綴(biz-order-%d),排查堆疊事半功倍。
- 監控指標:
poolSize、activeCount、queueSize、rejectedCount 接入 Prometheus/Grafana 告警。
- 優雅關閉:
shutdown() + awaitTermination(timeout),避免任務遺失。
下篇將深入 ForkJoinPool、虛擬線程、動態調優實戰,敬請期待。
- 上一篇文章: Windows 下 Java 環境變量配置與 Tomcat 9 安裝圖文教程
- 下一篇文章: 《Thinking in Java》讀書筆記:第 14 章 類型信息(RTTI、反射、動態代理、空對象模式)
Copyright ©
程式碼之家 All Rights Reserved