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