【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )
文章目錄
- 一、線程池執行任務細節分析
- 二、線程池執行 execute 源碼分析
一、線程池執行任務細節分析
線程池執行細節分析 :
核心線程數 101010 , 最大小成熟 202020 , 非核心線程數 101010 , 非核心線程空閑存活時間 606060 秒 , 阻塞隊列大小 101010 個 ;
當有 Runnable 任務進入線程池后 ;
先查看 " 核心線程 " , 如果沒有核心線程 , 先 創建核心線程 ;
如果有核心線程 , 則 查看核心線程是否有空閑的 ;
如果有空閑的核心線程 , 直接將該任務分配給該空閑核心線程 ;
如果沒有空閑核心線程 , 則 查看核心線程數有沒有滿 ;
如果核心線程沒有滿 , 則 創建一個核心線程 , 然后執行該任務 ;
如果核心線程滿了 , 將該任務放入 " 阻塞隊列 " 中 , 查看阻塞隊列是否已滿 ;
如果阻塞隊列沒有滿 , 直接 將任務放入阻塞隊列中 ;
如果阻塞隊列滿了 , 則 查看是否能創建 " 非核心線程 " ;
如果能創建非核心線程 , 則 創建非核心線程 , 并執行該任務 ;
如果不能創建非核心線程 , 則 執行 " 拒絕策略 " ;
二、線程池執行 execute 源碼分析
查看傳入的 Runnable 任務是否為空 , 如果為空 , 就報異常 ;
if (command == null)throw new NullPointerException();獲取當前線程池的狀態 , 根據不同的狀態 , 執行不同的操作 ;
/** 進行以下三個步驟處理:** 1. 如果當前運行的線程 , 小于核心線程數 , 那么創建一個新的核心線程 , * 將傳入的任務作為該線程的第一個任務 . * 調用 addWorker 方法 , 會原子性檢查運行狀態和任務數量 ; * 如果在不應該添加線程的情況下執行添加線程操作 , 就會發出錯誤警報 ; * 如果該方法返回 false , 說明當前不能添加線程 , 此時就不要執行添加線程的操作了 ; ** 2. 如果任務被成功放入 線程池任務 隊列 , 不管我們此時是否應該添加線程 , 都需要進行雙重驗證 ;* 雙重驗證 : 添加到任務隊列時驗證一次 , 添加到線程執行時驗證一次 ; * 可能存在這種情況 , 在上次驗證線程運行狀態之后 , 有可能該線程就立刻被銷毀了 ;* 也可能存在進入該方法后 , 線程池被銷毀的情況 ; * 因此我們反復驗證線程狀態 , 如果需要在線程停止時回滾隊列 , 如果沒有線程就創建新線程 ;** 3. 如果不能將任務放入隊列中 , 嘗試創建一個新線程 ; * 如果創建線程失敗 , 說明當前線程池關閉 , 或者線程池中線程飽和 , 此時拒絕執行該任務 ; */int c = ctl.get();上述 AtomicInteger ctl 線程池狀態是很關鍵的原子變量 , 該原子變量中同時包含了線程池的線程數量 , 該值是一個組合的數值 ; 該 int 值 444 字節 323232 位 , 前 333 位是線程池的狀態位 , 剩下的 292929 位是線程數 ;
/*** 主池控制狀態ctl是一個原子整數* 兩個概念領域* workerCount,指示有效線程數* 運行狀態,指示是否運行、關閉等* * 為了將它們打包成一個整數,我們將workerCount限制為* (2^29)-1(約5億)個線程,而不是(2^31)-1(2* 10億)否則可代表。如果這曾經是一個問題* 將來,變量可以更改為原子長度,* 下面的移位/遮罩常數已調整。但在需要之前* 因此,此代碼使用int更快更簡單。* * workerCount是已注冊的工人數* 允許啟動,不允許停止。該值可能是* 與活動線程的實際數量暫時不同,* 例如,ThreadFactory在以下情況下無法創建線程:* 當退出線程仍在執行時* 終止前的簿記。用戶可見池大小為* 報告為工作集的當前大小。* * 運行狀態提供主要的生命周期控制,具有以下值:* * 正在運行:接受新任務和處理排隊的任務* 關機:不接受新任務,但處理排隊的任務* 停止:不接受新任務,不處理排隊的任務,* 并中斷正在進行的任務* 整理:所有任務都已終止,workerCount為零,* 正在轉換為狀態整理的線程* 將運行終止的()鉤子方法* 終止:終止()已完成* * 這些值之間的數字順序很重要,以允許* 有序比較。運行狀態隨時間單調增加* 時間,但不需要擊中每個狀態。這些轉變是:* * 運行->關機* 在調用shutdown()時,可能隱式地在finalize()中* (運行或關閉)->停止* 在調用shutdownNow()時* 關機->整理* 當隊列和池都為空時* 停止->整理* 當池為空時* 清理->終止* 當終止的()鉤子方法完成時* * 等待終止()的線程將在* 國家終止。* * 檢測從關閉到清理的過渡較少* 比您希望的簡單,因為隊列可能會* 非空后為空,關機狀態下為空,但* 只有在看到它是空的之后,我們才能終止* workerCount為0(有時需要重新檢查——請參閱* 下)。*/private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));private static final int COUNT_BITS = Integer.SIZE - 3;private static final int CAPACITY = (1 << COUNT_BITS) - 1;// runState is stored in the high-order bitsprivate static final int RUNNING = -1 << COUNT_BITS;private static final int SHUTDOWN = 0 << COUNT_BITS;private static final int STOP = 1 << COUNT_BITS;private static final int TIDYING = 2 << COUNT_BITS;private static final int TERMINATED = 3 << COUNT_BITS;// Packing and unpacking ctlprivate static int runStateOf(int c) { return c & ~CAPACITY; }private static int workerCountOf(int c) { return c & CAPACITY; }private static int ctlOf(int rs, int wc) { return rs | wc; }簡單的機翻了下 , 如果查看詳細的英文注釋 , 查看 libcore/ojluni/src/main/java/java/util/concurrent/ThreadPoolExecutor.java 源碼 ;
線程池的狀態如下 , 有 555 種狀態 ;
// runState is stored in the high-order bitsprivate static final int RUNNING = -1 << COUNT_BITS;private static final int SHUTDOWN = 0 << COUNT_BITS;private static final int STOP = 1 << COUNT_BITS;private static final int TIDYING = 2 << COUNT_BITS;private static final int TERMINATED = 3 << COUNT_BITS;判斷當前的工作線程數 workerCountOf(c) 是否小于核心線程數 corePoolSize ;
如果小于 , 則添加核心線程 addWorker(command, true) ;
這里注意 , 來了新任務后 , 不是先將任務放入阻塞隊列 , 而是檢查核心線程 , 先嘗試將核心線程部署滿 ;
if (workerCountOf(c) < corePoolSize) {if (addWorker(command, true))return;c = ctl.get();}判斷當前的線程池狀態 isRunning(c) 是否正在執行處于 RUNNING 狀態 , 如果當前線程池處于 RUNNING 狀態 , 說明所有的核心線程都滿了 , 則將任務隊列放入阻塞隊列中 workQueue.offer(command) ;
如果可以入隊 , 重新檢查狀態 , 如果必要 回滾排隊 ! isRunning(recheck) && remove(command) , 重新檢查狀態通過后 , addWorker(null, false) 將任務添加如阻塞隊列中 ;
入隊失敗 , 嘗試添加非核心線程 !addWorker(command, false) , 如果非核心線程也失敗 , 則執行拒絕策略 reject(command) ;
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);總結
以上是生活随笔為你收集整理的【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java 并发编程】线程池机制 ( 线
- 下一篇: 【Java 并发编程】线程池机制 ( 线