線程池主要信息解析

  ThreadPoolExecutor是一個通過使用可能幾個池線程之一來執行每個提交任務的ExecutorService,這些線程池通常通過Executors工廠方法進行配置。

        ThreadPoolExecutor中的線程池處理了兩個不同的問題:

        1、由於減少了每個任務調用的開銷,在執行大量的異步任務時它們通常提供改進的性能;

        2、它們提供了邊界和管理資源的一種手段,包括多線程,在執行任務集合時的消耗。

        每個ThreadPoolExecutor還維護一些基本的統計數據,例如完成任務的數量。

        一、ThreadPoolExecutor中的重要成員變量

        1、AtomicInteger ctl

        AtomicInteger類型的ctl代表了ThreadPoolExecutor中的控制狀態,它是一個複覈類型的成員變量,是一個原子整數,藉助高低位包裝了兩個概念:

        (1)workerCount:線程池中當前活動的線程數量,佔據ctl的低29位;

        (2)runState:線程池運行狀態,佔據ctl的高3位,有RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED五種狀態。

        AtomicInteger ctl的定義如下:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
        先說下workerCount:線程池中當前活動的線程數量,它佔據ctl的低29位,這樣,每當活躍線程數增加或減少時,ctl直接做相應數目的增減即可,十分方便。而ThreadPoolExecutor中COUNT_BITS就代表了workerCount所佔位數,定義如下:

    private static final int COUNT_BITS = Integer.SIZE - 3;
        在Java中,一個int佔據32位,而COUNT_BITS的結果不言而喻,Integer大小32減去3,就是29;另外,既然workerCount代表了線程池中當前活動的線程數量,那麼
它肯定有個上下限閾值,下限很明顯就是0,上限呢?ThreadPoolExecutor中CAPACITY就代表了workerCount的上限,它是ThreadPoolExecutor中理論上的最大活躍線程數,其定義如下:
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
        運算過程爲1左移29位,也就是00000000 00000000 00000000 00000001 --> 001 0000 00000000 00000000 00000000,再減去1的話,就是 000 11111 11111111 11111111 11111111,前三位代表線程池運行狀態runState,所以這裏workerCount的理論最大值就應該是29個1,即536870911;
        既然workerCount作爲其中一個概念複合在AtomicInteger ctl中,那麼ThreadPoolExecutor理應提供從AtomicInteger ctl中解析出workerCount的方法,如下:

private static int workerCountOf(int c)  { return c & CAPACITY; }
        計算邏輯很簡單,傳入的c代表的是ctl的值,即高3位爲線程池運行狀態runState,低29位爲線程池中當前活動的線程數量workerCount,將其與CAPACITY進行與操作&,也就是與000 11111 11111111 11111111 11111111進行與操作,c的前三位通過與000進行與操作,無論c前三位爲何值,最終都會變成000,也就是捨棄前三位的值,而c的低29位與29個1進行與操作,c的低29位還是會保持原值,這樣就從AtomicInteger ctl中解析出了workerCount的值。
        接下來,我們再看下runState:線程池運行狀態,它佔據ctl的高3位,有RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED五種狀態。我們先分別解釋下這五種狀態:
        (1)RUNNING:接受新任務,並處理隊列任務

private static final int RUNNING    = -1 << COUNT_BITS;
        -1在Java底層是由32個1表示的,左移29位的話,即111 00000 00000000 00000000 00000000,也就是低29位全部爲0,高3位全部爲1的話,表示RUNNING狀態,即-536870912;
        (2)SHUTDOWN:不接受新任務,但會處理隊列任務

    private static final int SHUTDOWN   =  0 << COUNT_BITS;
        0在Java底層是由32個0表示的,無論左移多少位,還是32個0,即000 00000 00000000 00000000 00000000,也就是低29位全部爲0,高3位全部爲0的話,表示SHUTDOWN狀態,即0;
        (3)STOP:不接受新任務,不會處理隊列任務,而且會中斷正在處理過程中的任務

    private static final int STOP       =  1 << COUNT_BITS;

        1在Java底層是由前面的31個0和1個1組成的,左移29位的話,即001 00000 00000000 00000000 00000000,也就是低29位全部爲0,高3位爲001的話,表示STOP狀態,即536870912;
        (4)TIDYING:所有的任務已結束,workerCount爲0,線程過渡到TIDYING狀態,將會執行terminated()鉤子方法

    private static final int TIDYING    =  2 << COUNT_BITS;
        2在Java底層是由前面的30個0和1個10組成的,左移29位的話,即010 00000 00000000 00000000 00000000,也就是低29位全部爲0,高3位爲010的話,表示TIDYING狀態,即1073741824;
        (5)TERMINATED:terminated()方法已經完成

    private static final int TERMINATED =  3 << COUNT_BITS;
        2在Java底層是由前面的30個0和1個11組成的,左移29位的話,即011 00000 00000000 00000000 00000000,也就是低29位全部爲0,高3位爲011的話,表示TERMINATED狀態,即1610612736;
        由上面我們可以得知,運行狀態的值按照RUNNING-->SHUTDOWN-->STOP-->TIDYING-->TERMINATED順序值是遞增的,這些值之間的數值順序很重要。隨着時間的推移,運行狀態單調增加,但是不需要經過每個狀態。那麼,可能存在的線程池狀態的轉換是什麼呢?如下:

        (1)RUNNING -> SHUTDOWN:調用shutdownNow()方法後,或者線程池實現了finalize方法,在裏面調用了shutdown方法,即隱式調用;

        (2)(RUNNING or SHUTDOWN) -> STOP:調用shutdownNow()方法後;

        (3)SHUTDOWN -> TIDYING:線程池和隊列均爲空時;

        (4)STOP -> TIDYING:線程池爲空時;

        (5)TIDYING -> TERMINATED:terminated()鉤子方法完成時。

        我們再來看下是實現獲取運行狀態的runStateOf()方法,代碼如下:

private static int runStateOf(int c)     { return c & ~CAPACITY; }
        ~是按位取反的意思,CAPACITY表示的是高位的3個0,和低位的29個1,而~CAPACITY則表示高位的3個1,2低位的9個0,然後再與入參c執行按位與操作,即高3位保持原樣,低29位全部設置爲0,也就獲取了線程池的運行狀態runState。
        最後,我們再看下原子變量ctl的初始化方法ctlOf(),代碼如下:

    private static int ctlOf(int rs, int wc) { return rs | wc; }
        很簡單,傳入的rs表示線程池運行狀態runState,其是高3位有值,低29位全部爲0的int,而wc則代表線程池中有效線程的數量workerCount,其爲高3位全部爲0,而低29位有值得int,將runState和workerCount做或操作|處理,即用runState的高3位,workerCount的低29位填充的數字,而默認傳入的runState、workerCount分別爲RUNNING和0。
        2、BlockingQueue<Runnable> workQueue
        workQueue是用於持有任務並將其轉換成工作線程worker的隊列;

        3、HashSet<Worker> workers

        workers是包含線程池中所有工作線程worker的集合,僅僅當擁有mainLock鎖時才能訪問它;

        4、long completedTaskCount

        completedTaskCount是已完成任務的計數器,只有在worker線程的終止,僅僅當擁有mainLock鎖時才能訪問它;

        5、volatile ThreadFactory threadFactory

        創建新線程的工廠類;

        6、volatile RejectedExecutionHandler handler

        執行過程中shutdown時調用的handler;

        7、volatile long keepAliveTime

        空閒線程等待工作的超時時間(納秒),即空閒線程存活時間;

        8、volatile boolean allowCoreThreadTimeOut

        默認值爲false,如果爲false,core線程在空閒時依然存活;如果爲true,則core線程等待工作,直到時間超時至keepAliveTime;

        9、volatile int corePoolSize

        核心線程池大小,保持存活的工作線程的最小數目,當小於corePoolSize時,會直接啓動新的一個線程來處理任務,而不管線程池中是否有空閒線程;

        10、volatile int maximumPoolSize

        線程池最大大小,也就是線程池中線程的最大數量。

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