ThreadPoolExecutor中的keepAliveTime詳解

ThreadPoolExecutor中的keepAliveTime詳解

閱讀這篇文章,你將會知道:

  1. keepAliveTime的概念。
  2. keepAliveTime是如何設置的。
  3. 線程是如何根據keepAliveTime進行銷燬的。

一.keepAliveTime的概念:

  1. keepAliveTime的單位是納秒,即1s=1000000000ns,1秒等於10億納秒。
  2. keepAliveTime是線程池中空閒線程等待工作的超時時間。
  3. 當線程池中線程數量大於corePoolSize(核心線程數量)或設置了allowCoreThreadTimeOut(是否允許空閒核心線程超時)時,線程會根據keepAliveTime的值進行活性檢查,一旦超時便銷燬線程。
  4. 否則,線程會永遠等待新的工作。
    /**
     * Timeout in nanoseconds for idle threads waiting for work.
     * Threads use this timeout when there are more than corePoolSize
     * present or if allowCoreThreadTimeOut. Otherwise they wait
     * forever for new work.
     */
    private volatile long keepAliveTime;

二. keepAliveTime的設置方法

1.通過構造函數設置

通過 keepAliveTime 、unit共同決定實際的 keepAliveTime值,最終會轉化成納秒單位。

2.通過setKeepAliveTime方法動態設置

重新設置線程池的keepAliveTime屬性,如果發現將要設置的值比原來的keepAliveTime值要小(即減小keepAliveTime),則觸發interruptIdleWorkers(),中斷空閒線程。

interruptIdleWorkers()是怎麼中斷線程的呢?
(1)interruptIdleWorkers先拿出所有的工作者進行遍歷,判斷工作者對應的線程是否已經中斷。
(2)如果沒有產生中斷,則判斷是否可以獲得鎖,如果能獲得鎖,則代表是空閒線程,然後中斷該線程。
(3)至於線程的中斷在什麼時候會拋出中斷異常,同學們可以自己找下資料,也可以參考下別人寫的這篇文章Java併發之線程中斷

三.線程是如何根據keepAliveTime進行銷燬的

  1. 線程池中的線程通過工作者(Worker)這個類進行包裝,Worker通過 ThreadPoolExecutor.runWorker() 這個方法進行自旋,從隊列中獲得task,並完成工作。

  2. 如果拿不到task(即firstTask == null 或 getTask() == null),則會退出自旋,進入finally代碼塊。finally中會調用processWorkerExit方法,註銷當前Worker,實現worker的銷燬。對keepAliveTime的使用,就在getTask()方法中,這個在後面講解。

  3. getTask 怎麼使用 keepAliveTime
    (1)首先也是一個自旋,當allowCoreThreadTimeout(運行空閒核心線程超時) 或 wc>corePoolSize(當前線程數量大於核心線程數量) 時,timed會標識爲true,表示需要進行超時判斷。
    (2)當wc(當前工作者數量)大於 最大線程數 或 空閒線程的空閒時間大於keepAliveTime(timed && timeout),以及wc>1或(workQueue)任務隊列爲空時,會進入compareAndDecrementWorkerCount方法,對wc的值減1。
    (3)當compareAndDecrementWorkerCount方法返回true時,則getTask方法會返回null,終止getTask方法的自旋。這時候回到runWorker方法,就會進入到processWorkerExit方法,進行銷燬worker。

  4. compareAndDecrementWorkerCount中操作的是ctl屬性:
    (1)ctl是中心控制器,一個AtomicInteger類型的整數,通過數字的二進制編碼的位進行分段,不同的二進制位段表示有不同的含義。
    (2)在ctl中,低29爲表示線程池的容量,即線程池最大容量爲 536870911 = 000 11111111111111111111111111111。

	/**
     * The main pool control state, ctl, is an atomic integer packing
     * two conceptual fields
     *   workerCount, indicating the effective number of threads
     *   runState,    indicating whether running, shutting down etc
     */
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    // COUNT_BITS = 29
    private static final int COUNT_BITS = Integer.SIZE - 3;
    // CAPACITY = 536870911 = 000 11111111111111111111111111111
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;
    
	private static int workerCountOf(int c)  { 
		return c & CAPACITY; 
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章