(三)JDK線程池源碼分析2之線程生命週期

  • 概述
    JDK線程池源碼分析1中我已經將線程池的創建,線程池中線程的創建,線程執行任務的整個流程已經分析完畢了,這次主要是來分析單個線程在線程池中是如何工作的以及如何被管理的.其實這個實現的流程主要在ThreadPoolExecutor的runWorker方法中進行實現的,對於runWorker是怎麼觸發的可以參考我的上一篇文章.

  • runWorker方法主流程
    在這裏插入圖片描述
    主要由三部分組成:
    a.獲取任務.如果是剛加入的線程可能存在firstTask,那麼執行創建線程分配的任務,如果不是剛加入的線程,那麼將會去任務隊列裏面獲取任務.
    b.執行任務
    3.工作線程退出.工作線程任務都執行完畢或者執行當中拋出異常,那麼將這個線程進行處理

  • getTask方法主流程
    在這裏插入圖片描述
    主要分爲兩部分:
    1.判斷當前線程是否要退出,這裏分爲很多中情況
    a.第一個if判斷當前線程池的狀態是不是SHUTDOWN(關閉)狀態,因爲線程池關閉狀態意味着只是拒絕接收任務,但很有可能還有線程在執行任務,或者當前任務隊列還有任務需要執行,如果任務隊列已經沒任務了,或者線程池的線程已經不活躍了,那麼當前線程就再也不需要了,那麼就可以關閉了,return null (調用的上層退出了while循環了,開始執行processWorkerExit)
    b.第二個if 假設我們讓核心線程沒有設置超時時間,即核心線程的個數一直存在allowCoreThreadTimeOut默認值false,如果在線程池只有核心線程池個數的時候,第二個if永遠爲false, 也就是在沒有設置核心線程數量的線程的超時時間,線程池中永遠都有核心個數線程.
    c.第二個if 假設我們讓核心線程沒有設置超時時間,即核心線程的個數一直存在allowCoreThreadTimeOut默認值false,如果當前線程數已經超過了核心線程數,那麼timed=true,並且timeOut=true(當前線程上次獲取任務就超時),並且當前任務隊列還沒任務可執行,那麼說明當前線程處於閒置狀態有段時間了,可以退出了.
    d.第二個if 假設我們讓核心線程有設置超時時間,即allowCoreThreadTimeOut==true,這個時候只要有超時記錄,並且當前任務隊列還是沒任務,那麼即使是核心線程也是需要在閒置的情況下退出.
    e.第二個if 假設我們原來覺得maximumPoolSize太大了,這個時候我們動態調整了這個參數,那麼會將線程池線程數量降到新的maximumPoolSize,然後後面還要不要退出更多的線程,會走上面的b,c,d策略
    2.經過上面判斷,這個線程還是需要的,那麼將直接獲取任務,並且返回任務給上層,這裏有兩個方法去獲取任務,分別是poll帶阻塞時間,take一直阻塞
    a.如果沒有設置核心線程的超時時間,那麼直接執行token,不會返回null,也就沒有核心線程超時說法,就不會記錄有超時的標記
    b.如果設置了核心線程的超時時間,那麼執行poll,如果在keepAliveTime的時間還沒拿到任務,那麼將標記爲當前線程有超時的標記,那麼再下一回將有可能退出當前線程.

  • processWorkerExit方法主流程
    在這裏插入圖片描述
    主要分爲三個組成部分
    1.將不再需要(空閒或者執行任務拋出異常)的線程從線程池中移除
    2.嘗試終止這個不需要(空閒或者執行任務拋出異常)的線程
    3.主要分爲線程兩種狀態的處理:
    a.completedAbruptly=false算正常退出,所以只要保證核心線程數量就可以了,在getTask方法我已經分析過線程池保存核心線程數量的策略了
    b.completedAbruptly=true表示是非正常退出,是執行任務拋出異常導致退出的,這個時候其實是需要這個線程的,那麼採用的策略直接是添加一個線程

  • 總結
    其實在上面幾個方法中已經完整描述了線程池中線程的生命週期:
    1.allowCoreThreadTimeOut=false(不允許核心線程超時,核心線程一直存在)
    a.在覈心線程夠用的情況下,核心線程照常執行任務,核心線程一直阻塞,直到獲取到隊列的任務; 這種情況下核心線程只有兩種情況會退出 1.線程池關閉 2.執行任務發生異常;在覈心線程退出後的處理中也分兩種情況,1.如果線程池處於停止狀態,那麼不處理;2如果線程池還是活躍狀態,那麼創建一個新的核心線程代替
    b.如果核心線程不夠用,那麼非核心線程是有超時時間的,那就是keepAliveTime這個參數,默認是0;如果非核心線程超時,那麼將直接退出這個線程.所以keepAliveTime這個參數非常重要,設置不好會頻繁刪除/添加非核心線程
    2.allowCoreThreadTimeOut=true(允許核心線程超時)
    在這種情況下,核心線程和非核心線程其實生命週期是一樣的,keepAliveTime這個參數對所有參數起效果,如果一超時,那麼線程就直接退出,在退出的處理中,也是一樣的,這個時候線程池的最小數量是可以爲0的.閒置沒有任務的話,所有線程都會退出.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章