上一篇介紹了線程池的設計需求與使用,本文深入剖析 java.util.concurrent.ThreadPoolExecutor 核心實現。分析優秀框架原始碼是提升架構設計能力的最佳途徑:既能學習設計模式在實戰中的運用,又能理解併發控制的精髓。JDK 併發包更是教科書級範例,值得反覆研讀。
HashSet<Worker>)與任務佇列(BlockingQueue<Runnable>)Runnable/Callable,線程池不依賴具體業務邏輯run() → 循環直到佇列為空或線程池關閉private final class Worker implements Runnable {
final Thread thread;
Runnable firstTask;
// ... 其他欄位
public void run() {
Runnable task = firstTask;
firstTask = null;
while (task != null || (task = getTask()) != null) {
try {
beforeExecute(thread, task);
task.run();
afterExecute(task, null);
} catch (Throwable ex) {
afterExecute(task, ex);
} finally {
task = null;
}
}
// 執行緒結束清理...
}
}
關鍵點:
Runnable,封裝真正的執行緒 ThreadfirstTask 支援提交任務時直接啟動執行緒執行,減少佇列延遲getTask() 從佇列獲取任務,支援超時回收beforeExecute/afterExecute 提供擴展點ThreadPoolExecutor 引入兩個關鍵參數控制執行緒數量動態調整:
public void execute(Runnable command) {
int c = ctl.get();
// 1. 低於核心數 → 直接新增核心執行緒執行
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true)) return;
c = ctl.get();
}
// 2. 核心數已滿 → 嘗試入佇列
if (isRunning(c) && workQueue.offer(command)) {
// 再次檢查狀態,若線程池已關閉則移除任務並拒絕
if (!isRunning(recheck) || remove(command)) reject(command);
// 若佇列有任務但無執行緒(corePoolSize=0),確保至少有一個執行緒
else if (workerCountOf(recheck) == 0) addWorker(null, false);
}
// 3. 佇列滿 → 嘗試新增非核心執行緒
else if (!addWorker(command, false)) {
// 4. 達最大數仍失敗 → 執行拒絕策略
reject(command);
}
}
提交任務
│
├─ 當前執行緒數 < corePoolSize ──► 建立核心執行緒執行(提高吞吐)
│
├─ 當前執行緒數 ≥ corePoolSize ──► 任務入佇列
│ │
│ ├─ 入佇列成功 ──► 等待核心執行緒處理
│ │
│ └─ 入佇列失敗(佇列滿)──► 當前執行緒數 < maximumPoolSize
│ │
│ ├─ 是 ──► 建立非核心執行緒處理(降低失敗率)
│ │
│ └─ 否 ──► 執行 RejectedExecutionHandler 拒絕策略
單一 AtomicInteger ctl 同時封裝「執行緒池狀態」與「執行緒計數」,透過位運算高效實現狀態轉換與計數更新,避免鎖競爭。
private Runnable getTask() {
for (;;) {
// 根據 allowCoreThreadTimeOut 決定核心執行緒是否超時回收
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS)
: workQueue.take();
if (r != null) return r;
if (timed && wc > corePoolSize) {
if (compareAndDecrementWorkerCount(c)) return null; // 回收執行緒
}
}
}
shutdown():設定狀態為 SHUTDOWN,中斷空閒執行緒,已提交任務繼續執行shutdownNow():設定狀態為 STOP,中斷所有執行緒,返回未執行任務列表interruptIdleWorkers() 遍歷 Worker 集合呼叫 thread.interrupt()ArrayBlockingQueue)配合 CallerRunsPolicy,避免 OOM 並實現背壓CPU核心數+1;IO 密集型參考 CPU核心數 * (1 + 平均等待時間/平均工作時間)getTaskCount()、getCompletedTaskCount()、getActiveCount()、getQueue().size() 建構儀表板ThreadFactory 加入業務前綴(如 order-processor-%d),排查問題事半功倍ThreadPoolExecutor 展現了頂級併發框架的設計智慧:原子狀態控制、無鎖計數、模板方法擴展、優雅生命週期管理。深入理解其內部機制,不僅能避免生產環境踩坑(如 CachedThreadPool OOM、FixedThreadPool 任務積壓),更能在設計自訂併發組件時借鑑其精髓。下一篇將探討 ScheduledThreadPoolExecutor 定時任務調度機制,敬請期待。