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
線程池最大大小,也就是線程池中線程的最大數量。