1.設計層面 首先要有任務抽象,這裡可以是Runnable及Callable的實作類別。有了任務後,執行任務的一般是線程,但如果當前線程不夠時希望任務能夠被暫時緩衝,之後有空閑線程後再被消費。所以就有了任務隊列。 空閑線程就是從這個隊列取任務進行處理,可以將這個職責抽象一個Worker類。 然後有一個核心流程服務類,執行使用者提交的任務,如果無線程可用時執行相應的往任務隊列塞任務或拒絕等邏輯。 這個核心流程實作類別就是ThreadPoolExecutor。 2.任務加入到線程池程式碼分析 類是:ThreadPoolExecutor 基本流程對應流程圖,可參考深入線程池一。 代碼如下:
public void execute(Runnable command) { if (command == null) throw new NullPointerException(); int c = ctl.get(); if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } 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); } else if (!addWorker(command, false)) reject(command); }
ctl 是一個 AtomicInteger 類型, 它的 低29位 用於存放當前的線程數, 因此一個線程池在理論上最大的線程數是 536870911; 高 3 位是用於表示當前線程池的狀態, 其中高三位的值和狀態對應如下: 111: RUNNING 000: SHUTDOWN 001: STOP 010: TIDYING 110: TERMINATED
代碼流程如下: 1.首先校正入參任務是否為空白,為空白拋異常 2.擷取ctl,【int c = ctl.get(); 】這裡剛進來時是:-536870912 3.[workerCountOf(c) ]用於擷取當前已有線程數,如果小於核心線程數則執行: if (workerCountOf(c) < corePoolSize) { if (addWorker(command, true)) return; c = ctl.get(); } 這裡的addWorker(command, true))用於建立新的worker邏輯。以下會分析。 這裡只要知道如果建立新的Worker成功後,會返回給調用方,此時表示已經建立了一個Worker用於處理這個任務。
4.否則嘗試將任務提交到任務隊列 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); } 這裡必須要求整個線程池狀態必須是Running狀態。即如果線程處理於SHUTDOWN,STOP,TIDYING,TERMINATED等狀態時是不會再將任務加入到任務隊列。即然要關閉線程池,就不要再加入任務到隊列了,沒意義。 這裡可以看到,如果在加入到隊列後,還會再次檢查線程池狀態,如果這裡變成不可用狀態則會執行拒絕策略。 這裡的使用意義在於,如果外部調用shutdown方法,在執行到這段代碼時,會執行相應的拒絕策略,如果使用預設的拒絕策略則當前任務不會被執行。如果使用的是以阻塞的形式往隊列加任務時,則任務還是會被執行。
5.如果隊列已滿,執行以下代碼,這裡主要是想看能否建立線程來執行 else if (!addWorker(command, false)) reject(command);
可以看到當前如果線程數已經大於【最大線程數】則會執行【reject(command)】來執行拒絕策略。
6.addWorker方法,職責是想辦法建立新的Worker來執行任務,代碼如下: 方法參數:【boolean core】表示是否是小於核心線程數的邏輯,這個方法對於小於核心線程數及大於核心線程數的兩種情況都可以複用。 然後主要邏輯分成兩塊: a.cas設定線程數大小,失敗重試 b.建立Worker執行任務
private boolean addWorker(Runnable firstTask, boolean core) { retry: for (;;) { int c = ctl.get();//擷取狀態及當前線程數值,共32位,高3位用於儲存狀態,低29位用於儲存線程數 int rs = runStateOf(c); // 這裡需要保證後續shutdown時,worker退出處理時要求在隊列還有任務時,並且當前沒有線程執行任務時,這裡不會返回失敗 if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false; for (;;) { int wc = workerCountOf(c); if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; if (compareAndIncrementWorkerCount(c)) break retry; c = ctl.get(); // Re-read ctl if (runStateOf(c) != rs) continue retry; // else CAS failed due to workerCount change; retry inner loop } } boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try { w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { // Recheck while holding lock. // Back out on ThreadFactory failure or if // shut down before lock acquired. int rs = runStateOf(ctl.get());//線程池還是running狀態,或者雖然是shutdown,但還有任務需要執行,這時是由Worker退出時會調用這塊代碼 if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); int s = workers.size(); if (s > largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } if (workerAdded) { t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); } return workerStarted; }