一、線程池核心流程圖
+-----------------+
| 提交任務 | submit/execute
+-----------------+|v
+-----------------+
| 判斷核心線程數 | < corePoolSize?
+-----------------+|Yes |Nov v
[創建新線程] +-----------------+| 隊列是否滿? |+-----------------+|No |Yesv v[入隊列排隊] +------------------+| 判斷最大線程數 |+------------------+|No |Yesv v[創建新線程] [執行拒絕策略]
二、線程池主要環節及源碼方法
1. 任務提交(execute/submit)
方法:
execute(Runnable command)
submit(Runnable/Callable)
源碼片段:
public void execute(Runnable command) {if (command == null)throw new NullPointerException();int c = ctl.get();if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}if (isRunning(c) && workQueue.offer(command)) {int recheck = ctl.get();if (!isRunning(recheck) && remove(command))reject(command);else if (workerCountOf(recheck) == 0)addWorker(null, false);}else if (!addWorker(command, false))reject(command);
}
注釋速記:
- 任務先嘗試用核心線程處理。
- 核心線程滿則嘗試入隊列。
- 隊列滿則嘗試新建非核心線程。
- 實在不行,執行拒絕策略。
口訣:
先核心,后隊列;隊列滿,再擴容;全滿員,拒絕它。
2. 核心線程判斷與創建
方法:
addWorker(Runnable firstTask, boolean core)
源碼片段:
private boolean addWorker(Runnable firstTask, boolean core) {retry:for (;;) {int c = ctl.get();int rs = runStateOf(c);// ...省略狀態判斷for (;;) {int wc = workerCountOf(c);if (wc >= CAPACITY ||wc >= (core ? corePoolSize : maximumPoolSize))return false;if (compareAndIncrementWorkerCount(c))break retry;c = ctl.get();if (runStateOf(c) != rs)continue retry;}}// ...真正創建Worker線程
}
注釋速記:
- 根據core參數決定是否用核心線程池大小。
- 用CAS增加線程計數,線程安全。
口訣:
核心先上,CAS搶位,線程安全,才創建。
3. 入隊列
方法:
workQueue.offer(command)
源碼片段:
if (isRunning(c) && workQueue.offer(command)) {// 入隊成功后可能需要喚醒線程
}
注釋速記:
- 隊列沒滿則入隊。
- 入隊后如果線程都在忙,線程池不會立刻擴容。
口訣:
隊列能放,直接排隊。
4. 非核心線程擴容
邏輯:
- 當核心線程和隊列都滿時,允許創建新線程(最大線程數以內)。
源碼片段:
else if (!addWorker(command, false))reject(command);
注釋速記:
- 只有在核心線程和隊列都滿時才會擴容到最大線程數。
口訣:
滿員排隊,再擴容。
5. 拒絕策略
方法:
RejectedExecutionHandler.rejectedExecution(Runnable r, ThreadPoolExecutor e)
源碼片段:
public static class AbortPolicy implements RejectedExecutionHandler {public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {throw new RejectedExecutionException();}
}
注釋速記:
- 線程池和隊列都滿時,根據策略處理(拋異常/丟棄/調用者執行等)。
口訣:
全都滿員,策略管。
6. 線程回收與銷毀
方法:
worker.run()
- 判斷空閑時間超過keepAliveTime
源碼片段:
while (task != null || (task = getTask()) != null) {// 執行任務
}
注釋速記:
- 非核心線程空閑時間到達后會被回收。
- 核心線程默認不會被回收(可通過allowCoreThreadTimeOut配置)。
口訣:
閑太久,自動走。
三、流程口訣速記
提任務,先核心,隊列排,擴滿員;全滿員,策略管;空閑久,自動走。
四、常用方法與內部邏輯簡表
階段 | 關鍵方法/類 | 主要邏輯說明 |
---|---|---|
任務提交 | execute/submit | 任務進線程池 |
核心線程判斷 | addWorker(core=true) | 核心線程是否有空位,有則新建 |
入隊列 | workQueue.offer | 核心線程滿,隊列沒滿則排隊 |
非核心線程 | addWorker(core=false) | 隊列滿,是否可新建非核心線程 |
拒絕策略 | RejectedExecutionHandler | 全部滿員,執行拒絕策略 |
線程回收 | allowCoreThreadTimeOut | 非核心線程閑置超時自動銷毀 |
五、源碼脈絡圖(偽代碼)
execute(command) {if (核心線程未滿)addWorker(command, true) // 新核心線程else if (隊列未滿)workQueue.offer(command) // 入隊列else if (線程池未滿)addWorker(command, false) // 新非核心線程elsereject(command) // 拒絕策略
}
六、速記口訣總結
場景 | 口訣 |
---|---|
任務進池 | 先核心,后隊列 |
隊列滿了 | 再擴容(到最大線程數) |
全滿員 | 策略管(拒絕策略) |
線程回收 | 閑太久,自動走 |
全流程 | 提任務,先核心,隊列排,擴滿員;全滿員,策略管;空閑久,自動走。 |
七、配圖(流程圖)
+-------------------------+| 提交任務 |+-------------------------+|+-------------+-------------+| |
+-----v-----+ +-----v-----+
| 核心線程? |----是-------->| 創建線程 |
+-----------+ +-----------+|否|
+-----v-----+
| 隊列滿? |----否-------> 入隊列
+-----------+|是|
+-----v-----+
| 最大線程? |----否-------> 創建線程
+-----------+|是|
+-----v-----+
| 拒絕策略 |
+-----------+
八、結語
通過以上細化,線程池的工作原理、源碼關鍵點、方法流程、口訣速記都一目了然。
只要記住口訣和流程圖,結合源碼細節,面試和實戰都能輕松拿捏!