ThreadPoolExecutor源碼分析(一)
一、前言
閑來無事,博主有重新翻看了一下jdk1.8版的ThreadPoolExecutor源碼,看後寫此筆記,畫個圈圈,做個記錄,這段源碼,我看過,到處一遊,嘻嘻~~
二、ThreadPoolExecutor數據結構
在ThreadPoolExecutor的內部,主要由BlockingQueue和AbstractQueuedSynchronizer對其提供支持。在鎖框架中,AbstractQueuedSynchronizer抽象類可以毫不誇張的說,占據著核心地位,它提供了一個基於FIFO隊列,可以用於構建鎖或者其他相關同步裝置的基礎框架。
三、ThreadPoolExecutor源碼分析
類的結構圖:
通過查看ThreadPoolExecutor源碼的構造函數,corePoolSize(核心線程數),maximumPoolSize(最大線程數),keepAliveTime(當線程池中線程數目>核心線程數,空閑的線程等待任務,即Runnable的時間,超過該時間,該空閑線程將被終止),workQueue(阻塞隊列,當線程池線程數>核心線程數時,新來的Runnable任務將放到阻塞隊列中,待 Worker獲取執行),threadFactory(線程工廠類,創建新的Thread),RejectedExecutionHandler線程拒絕策略,默認是AbortPolicy(拋出RejectedExecutionException異常)
前提:
線程池的五種狀態:
RUNNING(線程池正常運行),SHOUDOWN(不接收提交的新Runnable任務,會接著處理阻塞隊列裏面的任務),STOP(不接收提交的新Runnable任務,不處理阻塞隊列裏面的任務,中斷正在處理的任務)
TIDYING(所有的線程都被終止,執行自定義的鉤子方法terminated()
),TERMINATED(線程池終止,終極狀態)
接下來,來看線程池提交方法execute(註:submit方法內部也是會調用execute)
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); }
1:若當前線程池線程數目 < 核心線程數目 ,直接把Runable任務加入新建的Worker中,並啟動任務。
2:若線程池正常(ctl == RUNNING),直接創建一個新的Woker,即開啟一個新的線程執行Runnable任務。
3: 若線程池線程數目>核心線程數目,並且阻塞隊列未滿,添加到阻塞隊列中,並進行二次判斷當前線程池是否還是正常運行的(ctl==Runnable)
becasuse: 若在此時調用了shutdown () or shoutdownNow()方法的話,說明線程池已經發出終止請求,不應該在把新的任務添加到阻塞隊列中,並且執行拒絕策略。
4: 線程池允許的最大線程數目>若線程池線程數目>核心線程數目 & 阻塞隊列已滿, 新建Woker線程執行Runnable任務。
5: 若線程池線程數目>=線程池允許的最大線程數目,對於新提交的任務執行拒絕策略。
在這一連串的邏輯判斷中,需要註意一下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)) 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()); 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; }
該方法先判斷線程池狀態是否發生改變(是否還是RUNNING狀態),若不是直接返回false,判斷線程池當前線程數目是否大於核心線程數目,超過返回false.
否則新建woker線程,並把新建線程加入到wokers的集合中,啟動新建的線程。
啟動新建線程會調用Worker實例裏面的run方法,run方法中調了runWorker方法,研究一下這個方法:
final void runWorker(Worker w) { Thread wt = Thread.currentThread(); Runnable task = w.firstTask; w.firstTask = null; w.unlock(); // allow interrupts boolean completedAbruptly = true; try { while (task != null || (task = getTask()) != null) { w.lock(); if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) wt.interrupt(); try { beforeExecute(wt, task); Throwable thrown = null; try { task.run(); } catch (RuntimeException x) { thrown = x; throw x; } catch (Error x) { thrown = x; throw x; } catch (Throwable x) { thrown = x; throw new Error(x); } finally { afterExecute(task, thrown); } } finally { task = null; w.completedTasks++; w.unlock(); } } completedAbruptly = false; } finally { processWorkerExit(w, completedAbruptly); } }
如果傳入的任務不為空,則先執行傳入的任務,執行完成後去阻塞隊列中獲取任務執行。
若傳入的任務為空,則直接去阻塞隊列裏面獲取任務執行。
若阻塞隊列為空,則runWorker 執行finally代碼塊。線程池工作線程數目-1,把這個woker從wokers集合移除,並且中斷改woker線程。
, 今天就更新到這,下次持續更新ing..................
ThreadPoolExecutor源碼分析(一)