J2SE 5.0 (java.util.concurrent) 引入工業級線程池框架,徹底改變 Java 多線程開發模式。本文深度解析 ThreadPoolExecutor 核心架構、兩大關鍵概念、任務提交與執行流程、關閉機制,並提供最佳實踐建議。
為什麼需要線程池?三大核心理由
- 效能提升:線程建立/銷毀系統開銷大,池化重用避免頻繁上下文切換與記憶體分配。
- 關注點分離:業務邏輯 (Task) 與線程生命週期管理解耦。開發者只提交
Runnable/Callable,池負責排程、佇列、線程回收。
- 資源可控與穩定性:限制同時活動線程數,防止 OOM、CPU 競爭過度,實現優雅降級 (拒絕策略)。
核心架構:Executor 體系
java.util.concurrent.Executor (介面)
▲
│
java.util.concurrent.ExecutorService (介面) // 生命週期管理:shutdown, submit, invokeAll...
▲
│
java.util.concurrent.ThreadPoolExecutor (實作類) // 核心實作,高度可配置
ThreadPoolExecutor 七大建構參數
public ThreadPoolExecutor(
int corePoolSize, // 核心線程數 (常駐)
int maximumPoolSize, // 最大線程數 (峰值)
long keepAliveTime, // 非核心線程閒置存活時間
TimeUnit unit, // 時間單位
BlockingQueue workQueue, // 任務佇列
ThreadFactory threadFactory, // 線程工廠 (命名、優先權、daemon)
RejectedExecutionHandler handler // 拒絕策略 (佇列滿 + 線程達最大)
)
兩大關鍵動態概念:Sizes 與 Queues
線程池大小動態調整
corePoolSize:最小常駐線程數。啟動時不建立,首次任務到達才創建 (除非 prestartAllCoreThreads())。
maximumPoolSize:上限。當佇列滿且線程數 < maximum 時創建新線程。
getPoolSize():當前實際線程數。
任務佇列策略
- 無界佇列 (如
LinkedBlockingQueue):任務無限堆積,maximumPoolSize 失效,僅 corePoolSize 生效。
- 有界佇列 (如
ArrayBlockingQueue(100)):佇列滿則嘗試擴充線程至 maximumPoolSize,仍滿則觸發拒絕策略。
- 同步移交佇列 (
SynchronousQueue):不儲存任務,直接移交給線程。無閒置線程則創建新線程 (至 maximum),否則拒絕。適合高吞吐、任務輕量場景。
任務提交與執行完整決策流程
呼叫 execute(task) 時,依序判斷:
- 線程數 < corePoolSize → 立即創建新線程 執行 (即使有閒置線程)。
- core ≤ 線程數 < maximum 且 有閒置線程 → 閒置線程執行。
- core ≤ 線程數 < maximum 且 無閒置線程 → 嘗試入佇列 (不阻塞)。成功則等待;失敗 (佇列滿) → 創建新線程 執行。
- 線程數 = maximum 且 無閒置線程 → 嘗試入佇列。成功等待;失敗 → 觸發 RejectedExecutionHandler。
任務完成後的線程回收邏輯
- 線程數 > corePoolSize:線程等待新任務,超時 (
keepAliveTime) 後 退出縮減。若 keepAliveTime=0,任務完成即退出 (忽略 core)。
- 線程數 ≤ corePoolSize:線程 無限期阻塞等待 新任務 (除非 timeout=0)。
關閉機制:優雅停機 vs 立即停機
| 方法 | 行為 | 回傳值 |
shutdown() | 停止接受新任務,處理完佇列現有任務 | void |
shutdownNow() | 嘗試中斷執行中任務,返回未處理任務列表 | List<Runnable> |
awaitTermination(timeout, unit) | 阻塞等待池終止,配合 shutdown 使用 | boolean |
實戰最佳實踐
- 使用 Executors 工廠方法快速開始:
ExecutorService fixed = Executors.newFixedThreadPool(10); // core=max=10, 無界佇列
ExecutorService cached = Executors.newCachedThreadPool(); // core=0, max=Integer.MAX, SynchronousQueue
ExecutorService single = Executors.newSingleThreadExecutor(); // 序列化執行
ExecutorService scheduled = Executors.newScheduledThreadPool(5); // 定時/週期任務
- 生產環境建議自訂 ThreadPoolExecutor:明確命名線程 (
ThreadFactoryBuilder)、有界佇列防 OOM、自訂拒絕策略 (記錄日誌、持久化、降級處理)。
- 任務設計:實作
Runnable (無回傳) 或 Callable (有回傳/拋出異常),避免長時間阻塞 I/O 佔用核心線程 (考慮分離 I/O 池)。
- 監控指標:
getActiveCount()、getQueue().size()、getCompletedTaskCount()、getRejectedExecutionHandler() 統計。
完整範例:自訂線程池與優雅關閉
public class ThreadPoolDemo {
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor executor = new ThreadPoolExecutor(
5, 10, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(100),
new ThreadFactoryBuilder().setNameFormat("OrderProcessor-%d").build(),
new ThreadPoolExecutor.AbortPolicy() // 或自訂 RejectedExecutionHandler
);
// 提交 100 個任務
for (int i = 0; i < 100; i++) {
final int taskId = i;
executor.execute(() -> {
System.out.printf("[%s] Processing task %d%n", Thread.currentThread().getName(), taskId);
try { Thread.sleep(100); } catch (InterruptedException e) { Thread.currentThread().interrupt(); }
});
}
// 優雅關閉
executor.shutdown();
if (!executor.awaitTermination(60, TimeUnit.SECONDS)) {
System.err.println("Timeout, forcing shutdown...");
executor.shutdownNow();
}
System.out.println("All tasks completed.");
}
}
總結
J2SE 5.0 線程池框架將「線程管理」從業務代碼中抽離,提供工業級的可配置性、穩定性與監控能力。掌握 core/maximum、佇列類型、拒絕策略、關閉流程四大核心維度,是編寫高併發 Java 應用的必備技能。
- 上一篇文章: J2SE 核心技術深度解析:String 類特性、常用方法與效能陷阱全攻略
- 下一篇文章: 經典排序演算法 Java 實作全解析:氣泡、插入、選擇排序與效能比較
Copyright ©
程式碼之家 All Rights Reserved