【詳解】ThreadPoolExecutor原始碼閱讀(三)

貓毛·波拿巴發表於2018-11-02

系列目錄

執行緒數量的維護

執行緒池的大小有兩個重要的引數,一個是corePoolSize(核心執行緒池大小),另一個是maximumPoolSize(最大執行緒大小)。執行緒池主要根據這兩個引數對執行緒池中執行緒的數量進行維護。

需要注意的是,執行緒池建立之初是沒有任何可用執行緒的。只有在有任務到達後,才開始建立執行緒,並複用執行緒。

注:此圖不是狀態圖,不是說新增一個執行緒就直接到達corePoolSize狀態,而是要表示,一直新增執行緒直到達到corePoolSize。

註釋裡也寫的很清楚了:

(1)如果執行緒數未達核心數,則每接收一個任務就建立一個工作執行緒(這裡把Worker視為工作執行緒)來處理。

(2)如果執行緒數已達到核心數,那就把任務先放入佇列。等到有工作執行緒完成任務了,會自行從佇列中取任務做。

(3)如果任務無法放入佇列,如佇列是有界佇列,且已滿。那麼就會繼續建立工作執行緒來處理這個任務。注意,這裡的新執行緒已經不是核心執行緒了。

(4)如果執行緒數量已經達到maxPoolSize,這時候就是執行緒不能再建立了,任務也放不進佇列了,就得啟動reject策略。預設策略是AbortPolicy,也就是直接報異常。

public void execute(Runnable command) {
    //非空檢查
    if (command == null)
        throw new NullPointerException();
    
    //獲取執行緒池控制資訊
    int c = ctl.get();
    //通過workerCountOf方法獲取控制資訊內的工作執行緒數資訊
    //如果小於核心執行緒數,執行addWorker方法    0 => corePoolSize
    if (workerCountOf(c) < corePoolSize) {    
        //這個操作新增的是核心工作執行緒,且有初始任務
        if (addWorker(command, true))
            return; //如果操作成功直接返回
        //由於addWorker操作對工作執行緒數,可能有所更改,故重新獲取控制資訊
        c = ctl.get();
    }

    //新增核心執行緒失效後
    //如果執行緒池處於執行狀態,且任務成功加入阻塞佇列   corePoolSize => corePoolSize
    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);
    }
    //如果任務未能加入阻塞佇列,則新增非核心執行緒   corePoolSize => maxPoolSize
    //如果新增非核心執行緒也失敗,開啟拒絕策略
    else if (!addWorker(command, false))
        reject(command);      //maxPoolSize => maxPoolSize
}

 

相關文章