執行緒池核心優勢
避免頻繁建立/銷毀執行緒開銷,透過 Executor 介面解耦任務提交與執行,ThreadPoolExecutor 是核心實作(基於 JDK 1.7 源碼分析)。
生命週期狀態機
使用 AtomicInteger ctl 高 3 位表示狀態,低 29 位表示執行緒數:
| 狀態 | 說明 | 轉換條件 |
| RUNNING | 接受新任務,處理隊列任務 | 初始狀態 |
| SHUTDOWN | 拒絕新任務,處理隊列任務 | 呼叫 shutdown() |
| STOP | 拒絕新任務,拋棄隊列,中斷執行中任務 | 呼叫 shutdownNow() |
| TIDYING | 所有任務終止,執行緒數為 0 | 任務隊列空且無作用中執行緒 |
| TERMINATED | terminated() 執行完成 | TIDYING 狀態結束 |
四大核心參數與四種預設模型
| 參數 | 說明 |
| corePoolSize | 核心執行緒數(常駐,除非 allowCoreThreadTimeOut) |
| maximumPoolSize | 最大執行緒數(受限於 CAPACITY = 2^29-1) |
| keepAliveTime | 非核心執行緒閒置存活時間 |
| workQueue | 任務隊列(BlockingQueue 實作) |
| RejectedExecutionHandler | 拒絕策略(隊列滿且達最大執行緒時觸發) |
Executors 四種預設模型
| 模型 | core/max | 隊列 | 特性 | 適用場景 |
| FixedThreadPool | n/n | LinkedBlockingQueue (無界) | 固定大小,任務排隊 | 長期穩定負載 |
| CachedThreadPool | 0/Integer.MAX_VALUE | SynchronousQueue (直接交接) | 彈性伸縮,閒置回收 | 短期大量突發任務 |
| SingleThreadExecutor | 1/1 | LinkedBlockingQueue | 串行執行,保證順序 | 序列化任務處理 |
| ScheduledThreadPool | core/Integer.MAX_VALUE | DelayedWorkQueue | 定時/週期性任務 | 替代 Timer |
execute() 核心執行流程
public void execute(Runnable command) {
int c = ctl.get();
// 1. 執行緒數 < corePoolSize → 新建核心執行緒
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true)) return;
c = ctl.get();
}
// 2. 執行緒數 >= corePoolSize → 入隊列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
// 雙重檢查:狀態變更或執行緒為 0
if (!isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false); // 確保至少一個執行緒
}
// 3. 隊列滿 → 嘗試新建非核心執行緒
else if (!addWorker(command, false))
// 4. 失敗 → 拒絕策略
reject(command);
}
四階段運作模式
- Phase 1:poolSize < corePoolSize,隊列空 → 直接新建核心執行緒
- Phase 2:poolSize == corePoolSize → 任務入隊列,核心執行緒消費
- Phase 3:隊列滿,poolSize < maxPoolSize → 新建非核心執行緒
- Phase 4:poolSize == maxPoolSize 且隊列滿 → 觸發拒絕策略
Worker 內部類與 runWorker() 核心邏輯
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // 釋放 AQS 鎖
while (task != null || (task = getTask()) != null) {
w.lock(); // 獲取 AQS 獨佔鎖
try {
beforeExecute(wt, task); // 擴展點:子類覆寫
task.run();
afterExecute(task, null); // 擴展點
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
} finally {
task = null;
w.unlock();
}
}
processWorkerExit(w, false); // 清理
}
getTask() 任務獲取與執行緒回收
private Runnable getTask() {
boolean timed = allowCoreThreadTimeOut || workerCount > corePoolSize;
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : // 超時輪詢
workQueue.take(); // 阻塞等待
if (r == null) {
// 四種回收條件:
// 1. 執行緒數 > maximumPoolSize
// 2. 狀態 == STOP
// 3. 狀態 == SHUTDOWN 且隊列空
// 4. 超時且執行緒數 > corePoolSize
return null; // 觸發 processWorkerExit
}
return r;
}
四種拒絕策略對比
| 策略 | 行為 | 適用場景 |
| AbortPolicy (預設) | 拋出 RejectedExecutionException | 關鍵任務不可丟失,需即時感知 |
| CallerRunsPolicy | 呼叫者執行緒同步執行任務 | 緩衝壓力,不拋異常,不丟任務(推薦) |
| DiscardPolicy | 靜默丟棄任務 | 非關鍵、可容忍丟失的任務 |
| DiscardOldestPolicy | 丟棄隊列最舊任務,執行新任務 | 優先處理新請求的場景 |
自定義執行緒池最佳實踐
public class CustomThreadPool {
public static ThreadPoolExecutor create() {
return new ThreadPoolExecutor(
4, // corePoolSize: CPU 核心數 * (1 + 平均等待/計算比)
8, // maximumPoolSize
60L, TimeUnit.SECONDS, // keepAliveTime
new LinkedBlockingQueue<>(100), // 有界隊列,防止 OOM
new ThreadFactoryBuilder()
.setNameFormat("biz-worker-%d")
.setDaemon(false)
.build(),
new ThreadPoolExecutor.CallerRunsPolicy() // 推薦策略
);
}
// 擴展監控:覆寫 before/afterExecute
static class MonitoredPool extends ThreadPoolExecutor {
@Override protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
// 記錄任務開始時間、執行緒資訊
}
@Override protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
// 記錄耗時、異常、隊列積壓
}
}
}
隊列選型指南
| 隊列類型 | 特性 | 搭配建議 |
| ArrayBlockingQueue | 有界陣列、FIFO | 固定大小、公平鎖、預測負載 |
| LinkedBlockingQueue | 無界鏈表、FIFO | FixedThreadPool、可能 OOM 風險 |
| SynchronousQueue | 零容量、直接交接 | CachedThreadPool、即時執行 |
| PriorityBlockingQueue | 優先級排序 | 任務有優先級區分 |
| DelayedWorkQueue | 延遲執行排序 | ScheduledThreadPool 專用 |
監控關鍵指標
getActiveCount():正在執行任務的執行緒數
getQueue().size():待執行任務數(積壓指標)
getCompletedTaskCount():已完成任務總數
getTaskCount():總提交任務數
- 拒絕次數:自行計數或 JMX 監控