ThreadPoolExecutor是jdk內建線程池實作類別,現有的Executors工具類實現的幾種線程池核心都是調用ThreadPoolExecutor類。ThreadPoolExecutor在jdk1.7及以後做了部分修改,本文以JDK1.8為準。 1 建構函式
ThreadPoolExecutor類共有4個建構函式,其他三個建構函式都是調用下參數最全的一個,下面只介紹參數最全的的一個。
public ThreadPoolExecutor(int corePoolSize, //參數的意義已經在上一篇中介紹 int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { if (corePoolSize < 0 || //參數檢查 maximumPoolSize <= 0 || maximumPoolSize < corePoolSize || keepAliveTime < 0) throw new IllegalArgumentException(); if (workQueue == null || threadFactory == null || handler == null) throw new NullPointerException(); this.corePoolSize = corePoolSize; //設定基本線程數 this.maximumPoolSize = maximumPoolSize; //設定最大線程數 this.workQueue = workQueue; //設定任務隊列 this.keepAliveTime = unit.toNanos(keepAliveTime); //設定存活時間 this.threadFactory = threadFactory; //設定線程工廠 this.handler = handler; //設局拒絕策略 }
2 ThreadPoolExecutor類的方法
ThreadPoolExecutor類的主要方法有提交任務的execute()方法和submit()方法,終止線程的shutdown()方法和shutdowmNow方法。
execute方法用於提交任務,在Executor介面中聲明並在ThreadPoolExecutor類中實現。
submit方法用於提交任務並且有返回結果,在ExecutorService中聲明並且在AbstractExecutorService類中實現,ThreadPoolExecutor類並沒有重寫。
shutdown方法用於關閉線程池,但是允許正在啟動並執行任務運行完,將狀態置為SHUTDOWN。
shutdownNow方法在關閉線程池時嘗試終止正在啟動並執行任務,將狀態置為STOP。 3 ThreadPoolExecutor類重要方法源碼分析 3.1 execute方法源碼分析
execute方法在JDK1.7及以後具體實現做了重大修改,分析execute源碼之前先列舉ThreadPoolExecutor類定義的一些常量。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); //採用原子整型來記錄線程數量及狀態 private static final int COUNT_BITS = Integer.SIZE - 3; //線程池中線程數量存在低29位,高3位是線程池狀態 private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; // private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; // Packing and unpacking ctl private static int runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; } private static int ctlOf(int rs, int wc) { return rs | wc; }
線程池的五種狀態:
RUNNING 在ThreadPoolExecutor被執行個體化的時候就是這個狀態。
SHUTDOWN 通常是已經執行過shutdown()方法,不再接受新任務,等待線程池中和隊列中任務完成。
STOP 通常是已經執行過shutdownNow()方法,不接受新任務,隊列中的任務也不再執行,並嘗試終止線程池中的線程。
TIDYING 線程池為空白,就會到達這個狀態,執行terminated()方法。
TERMINATED terminated()執行完畢,就會到達這個狀態。
下面直接上代碼,程式碼分析放在注釋裡:
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(); //增加線程失敗,再次擷取變數。(其他線程可能改變了線程池中線程數量,線程也可能die) } if (isRunning(c) && workQueue.offer(command)) { //如果線程池還是RUNNING狀態就將任務加入工作隊列 int recheck = ctl.get(); //需要double check主要是時間差的問題,在上一句和這一句中間其他線程可能改變了線程池狀態 if (! isRunning(recheck) && remove(command)) //如果線程池狀態不再是RUNNING,則從工作隊列移除這個任務 reject(command); //移除任務成功,對這個任務使用拒絕策略 else if (workerCountOf(recheck) == 0) //如果線程池狀態是RUNNING,並且線程數量為0,說明基本線程數為0 addWorker(null, false); //線程池啟動一個線程,啟動後並不直接處理任務,並且判斷界限變為maximumPoolSize } else if (!addWorker(command, false)) //如果工作隊列已滿,則增加線程處理,線程判斷條件變為maximumPoolSize reject(command); }
忽略細節後總的邏輯如下:
第一,線程池中線程數量小於基本線程數(corePoolSize),則啟動新線程處理新的任務。
第二,線程池中線程數不小於基本線程數,則將任務加入工作隊列。
第三,工作隊列如果已滿,判斷線程數如果小於最大線程數(maximumPoolSize),則啟動新線程處理當前任務。
execute方法中最核心的方法就是addWorker方法,這個方法負責建立線程,下面重點分析洗addWorker源碼。
private boolean addWorker(Runnable firstTask, boolean core) { retry: for (;;) { int c = ctl.get(); int rs = runStateOf(c); //擷取線程池狀態 // Check if queue empty only if necessary. 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)) //如果線程池的狀態和線程數量都沒有改變,則將線程數量+1並且開始真正建立線程 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; //private final class Worker extends AbstractQueuedSynchronizer implements Runnable 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());//擷取線程狀態 if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) { //檢查線程池狀態 if (t.isAlive()) // precheck that t is startable throw new IllegalThreadStateException(); workers.add(w); //添加建立好的worker對象 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; }
3.2 shutdown方法源碼分析
shutdown方法關閉線程池時將線程池的狀態置為SHUTDOWN,不再接受新任務,等待隊列中的任務執行完成。
public void shutdown() { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { checkShutdownAccess(); //檢查當前線程是否有許可權終端線程池中的所有線程 advanceRunState(SHUTDOWN); //將線程池狀態改為SHUTDOWN interruptIdleWorkers(); //中斷空閑線程 onShutdown(); // hook for ScheduledThreadPoolExecutor } finally { mainLock.unlock(); } tryTerminate(); //將線程池狀態置為TERMINATED }
3.3 shutdownNow方法源碼分析
shutdownNow方法關閉線程池時將線程池的狀態置為STOP,並且停止隊列中進行中的任務。
public List<Runnable> shutdownNow() { List<Runnable> tasks; final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { checkShutdownAccess(); advanceRunState(STOP); //將線程池狀態改為STOP interruptWorkers(); tasks = drainQueue(); //和shutdown方法的區別就在於shutdownNow會停止正在處理的任務 } finally { mainLock.unlock(); } tryTerminate(); return tasks; }