簡介
ThreadPoolExecutor,Java線程池。使用線程池可以降低資源消耗,通過重複利用已創建的線程降低線程創建和銷燬造成的消耗;可以提高響應速度,當任務到達時,任務可以不需要的等到線程創建就能立即執行;可以提高線程的可管理性,防止無限制的創建線程,消耗系統資源。
下面首先通過初始化參數介紹一下線程池:
初始化參數
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;
}
corePoolSize:線程池的基本大小,核心線程數,當提交一個任務到線程池時,如果線程數小於核心線程數時,即使現有的線程空閒,線程池也會優先創建新線程來處理任務,而不是直接交給現有的線程處理,等到需要執行的任務數大於線程池基本大小時就不再創建。如果調用了線程池的prestartAllCoreThreads方法,線程池會提前創建並啓動所有基本線程。核心線程會一直存活,即使沒有任務需要處理,除非調用了allowCoreThreadTimeOut方法則允許核心線程超時終止。
maximumPoolSize:線程池最大大小,當線程數大於或等於核心線程,當任務隊列已滿,且已創建的線程數小於最大線程數,線程池會創建新的工作線程,直到線程數量達到maxPoolSize。如果線程數已等於maxPoolSize,且任務隊列已滿,則已超出線程池的處理能力,線程池會拒絕處理任務而拋出異常。
workQueue:任務隊列,用於保存等待執行的任務的阻塞隊列,當達到corePoolSize的時候,就向該等待隊列放入線程信息 。可以選擇以下幾個阻塞隊列。
- ArrayBlockingQueue:是一個基於數組結構的有界阻塞隊列,此隊列按 FIFO(先進先出)原則對元素進行排序。
- LinkedBlockingQueue:一個基於鏈表結構的阻塞隊列,此隊列按FIFO (先進先出) 排序元素,吞吐量通常要高於ArrayBlockingQueue。靜態工廠方法Executors.newFixedThreadPool()使用了這個隊列。
- SynchronousQueue:一個不存儲元素的阻塞隊列。每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQueue,靜態工廠方法Executors.newCachedThreadPool使用了這個隊列。
- PriorityBlockingQueue:一個具有優先級得無限阻塞隊列。
keepAliveTime:線程活動保持時間,線程池的工作線程空閒後,保持存活的時間。所以如果任務很多,並且每個任務執行的時間比較短,可以調大這個時間,提高線程的利用率。
unit:線程活動保持時間keepAliveTime的單位,可選的單位有天(DAYS),小時(HOURS),分鐘(MINUTES),毫秒(MILLISECONDS),微秒(MICROSECONDS, 千分之一毫秒)和毫微秒(NANOSECONDS, 千分之一微秒)。
threadFactory:用於設置創建線程的工廠,可以通過線程工廠給每個創建出來的線程設置更有意義的名字,Debug和定位問題時非常又幫助。
handler:飽和策略,當隊列和線程池都滿了,說明線程池處於飽和狀態,那麼必須採取一種策略處理提交的新任務。以下是JDK提供的策略。
- AbortPolicy:表示無法處理新任務時拋出異常
- CallerRunsPolicy:使用調用者所在線程來運行任務。
- DiscardOldestPolicy:丟棄隊列裏當前第一個任務,並重新提交當前任務。
- DiscardPolicy:不處理。
當然也可以根據應用場景需要來實現RejectedExecutionHandler接口自定義策略。如監控,記錄日誌或持久化不能處理的任務。
線程池執行任務流程
線程池按以下行爲執行任務:
- 當線程數小於核心線程數時,創建線程並執行任務。
- 當線程數大於等於核心線程數,且任務隊列未滿時,將任務放入任務隊列。
- 當線程數大於等於核心線程數,且任務隊列已滿。若線程數小於最大線程數,創建線程並執行任務;若線程數到達最大線程數,則拋出異常,拒絕任務。
源碼分析
ThreadPoolExecutor類繼承關係
ThreadPoolExecutor類繼承自AbstractExecutorService抽象類,AbstractExecutorService抽象類實現了ExecutorService接口,ExecutorService接口繼承自Executor接口。核心執行方法是Executor接口的execute()方法,ExecutorService擴展了submit(),invokeAll(),invokeAny()方法,並在AbstractExecutorService中做了具體實現,這三個方法最終都會調用Executor接口的execute()方法,execute()方法在ThreadPoolExecutor中做了具體實現。
public interface Executor {
void execute(Runnable command);//在將來某個時間執行給定任務。
}
public interface ExecutorService extends Executor {
void shutdown();//啓動一次順序關閉,執行以前提交的任務,但不接受新任務。
List<Runnable> shutdownNow();//試圖停止所有正在執行的活動任務,暫停處理正在等待的任務,並返回等待執行的任務列表。
boolean isShutdown();//如果此執行程序已關閉,則返回 true。
boolean isTerminated();//如果關閉後所有任務都已完成,則返回 true。
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;//請求關閉、發生超時或者當前線程中斷,無論哪一個首先發生之後,都將導致阻塞,直到所有任務完成執行。
<T> Future<T> submit(Callable<T> task);//提交一個返回值的任務用於執行,返回一個表示任務的未決結果的 Future。
<T> Future<T> submit(Runnable task, T result);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。
Future<?> submit(Runnable task);//提交一個 Runnable 任務用於執行,並返回一個表示該任務的 Future。
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException;//執行給定的任務,當所有任務完成時,返回保持任務狀態和結果的 Future 列表。
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;//執行給定的任務,當所有任務完成或超時期滿時(無論哪個首先發生),返回保持任務狀態和結果的 Future 列表。
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;//執行給定的任務,如果某個任務已成功完成(也就是未拋出異常),則返回其結果。
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;//執行給定的任務,如果在給定的超時期滿前某個任務已成功完成(也就是未拋出異常),則返回其結果。
}
ThreadPoolExecutor核心屬性
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));//原子的int類型計數器,高三位代表線程池狀態,低29位代表線程數量
private static final int COUNT_BITS = Integer.SIZE - 3;//代表線程數量,29位
private static final int CAPACITY = (1 << COUNT_BITS) - 1;//允許的最大線程數
/**
* 線程池狀態的轉換
* RUNNING -> SHUTDOWN:調用shutdown(),隱含在finalize()方法也會調用shutdown()
* (RUNNING or SHUTDOWN) -> STOP:調用shutdownnow()
* SHUTDOWN -> TIDYING:當隊列和池都是空的
* STOP -> TIDYING:當線程池是空的
* TIDYING -> TERMINATED:當terminated()方法完成了
**/
//線程池狀態
private static final int RUNNING = -1 << COUNT_BITS;//ctl高3位值是RUNNING的代表線程池狀態是運行:接受新的任務和進程隊列任務
private static final int SHUTDOWN = 0 << COUNT_BITS;//ctl高3位值是SHUTDOWN的代表線程池狀態是關閉:不接受新的任務,但處理隊列中的任務
private static final int STOP = 1 << COUNT_BITS;//ctl高3位值是STOP的代表線程池狀態是停止:不接受新的任務,不處理隊列中的任務,並中斷正在進行的任務
private static final int TIDYING = 2 << COUNT_BITS;//ctl高3位值是TIDYING的代表線程池狀態是整理中:所有任務已經終止,工作線程數是零,過渡到狀態爲整理中將運行terminated()方法
private static final int TERMINATED = 3 << COUNT_BITS;//ctl高3位值是TERMINATED的代表線程池狀態是終止:terminated()已完成
private final BlockingQueue<Runnable> workQueue;//任務隊列
private final ReentrantLock mainLock = new ReentrantLock();//線程池主鎖,操作線程池工作線程集合,線程池狀態等都需要先獲得該鎖
private final HashSet<Worker> workers = new HashSet<Worker>();//工作線程Worker集合,用於處理提交的任務或任務隊列中的任務
private int largestPoolSize;//記錄線程池有過的最大線程數,操作時需要獲取主鎖,通過鎖保證了可見性和原子性
private long completedTaskCount;//記錄線程池完成的任務數,工作線程退出時累加上去,操作時需要獲取主鎖,通過鎖保證了可見性和原子性
private volatile ThreadFactory threadFactory;//線程創建工廠,用來創建線程
private volatile RejectedExecutionHandler handler;//飽和策略
private volatile long keepAliveTime;//線程空閒時的存活時間,單位納秒
private volatile boolean allowCoreThreadTimeOut;//核心線程是否允許超時終止
private volatile int corePoolSize;//核心線程數量上限
private volatile int maximumPoolSize;//最大線程數量上限
ThreadPoolExecutor的工作線程Worker
Worker與其說是工作線程,其實是管理工作線程,每個Worker內部的線程在run方法中通過不斷的從任務隊列中獲取任務來不斷的處理任務,自身繼承自AQS,所以每個Worker自身也是一個鎖,保護獲取到的任務的執行,在鎖狀態意味着該Worker正在執行任務。除了創建Worker時提交的任務,其他提交過來的任務都是放入任務隊列交給Workers去消費的。
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
final Thread thread;//Work管理的線程,final保證構造函數內的操作在構造函數結束後都執行完成,而且對所有線程可見
Runnable firstTask;//第一個任務
volatile long completedTasks;//完成的任務計數
Worker(Runnable firstTask) {
setState(-1); //初始化並防止中斷該Worker
this.firstTask = firstTask;//創建時提交過來的第一個任務,啓動線程後將執行
this.thread = getThreadFactory().newThread(this);//通過線程工廠創建線程
}
public void run() {//運行方法
runWorker(this);
}
protected boolean isHeldExclusively() {//是否被鎖,1代表鎖已經被獲取,0代表鎖已經被釋放
return getState() != 0;
}
protected boolean tryAcquire(int unused) {//狀態由0到1代表成功獲取鎖
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {//狀態設置爲0代表釋放鎖
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }//獲取
public boolean tryLock() { return tryAcquire(1); }//嘗試獲取鎖
public void unlock() { release(1); }//釋放
public boolean isLocked() { return isHeldExclusively(); }//是否被鎖
void interruptIfStarted() {//如果已經啓動則中斷該線程
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();//獲取工作線程的Thread
Runnable task = w.firstTask;//將task設置爲Worker的第一個任務
w.firstTask = null;//將Worker中的第一個任務置爲null
w.unlock(); //無條件釋放鎖,其實是將鎖的狀態從初始化的-1設置爲0,代表鎖已經準備好,可以被獲取
boolean completedAbruptly = true;//代表runWorker停止的原因,當completedAbruptly爲true時代表worker停止是因爲worker執行的外部業務邏輯代碼拋出異常引起的。當completedAbruptly爲false時代表worker停止是線程池內部工作機制下的正常退出。
try {
while (task != null || (task = getTask()) != null) {//Worker的第一個任務不爲null,或者從任務隊列中獲取到任務,則執行,此處while循環調用getTask方法從任務隊列中獲取任務,直到超時獲取不到,或者線程池終止
w.lock();//Worker上鎖,保證不被shutDown方法中斷
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();//調用任務的run方法,這裏雖然是個Runnable但是並不需要創建線程來啓動,而是直接用線程池中的工作線程調用Runnable的run方法來執行。
} catch (RuntimeException x) {//若拋出異常則將異常向上拋出,終止該工作線程並從線程池中移除該Worker,因爲此處並非調用方直接調用,所以這個異常會被線程池喫掉,無法跟蹤記錄該異常棧,我們可以通過擴展點afterExecute來獲取拋出的異常,做相應的監控和記錄,以便於排查問題。
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;//清空當前task
w.completedTasks++;//該工作線程Worker完成過的任務數量
w.unlock();//釋放鎖
}
}
completedAbruptly = false;//正常退出則設置completedAbruptly爲false
} finally {
processWorkerExit(w, completedAbruptly);//處理Worker退出的邏輯
}
}
private Runnable getTask() {
boolean timedOut = false; //代表當前getTask方法上次poll是否超時未能獲取到task對象
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {//如果線程池狀態大於等於STOP,或者是SHUTDOWN且任務隊列是空
decrementWorkerCount();//減少線程數量
return null;//返回null後,Worker正常退出
}
boolean timed; //是否允許超時退出標記
for (;;) {//此處內層循環是爲了設置是否允許超時方式獲取任務,並且判斷當前是否可以以超時的方式退出
int wc = workerCountOf(c);
timed = allowCoreThreadTimeOut || wc > corePoolSize;//如果核心線程允許超時退出,或者線程數量大於核心線程數,則允許該次獲取任務超時退出
if (wc <= maximumPoolSize && ! (timedOut && timed))
break;//如果當前線程數量小於等於最大線程且並未超時或者當前線程池不允許超時退出,則跳出內層循環
if (compareAndDecrementWorkerCount(c))//如果當前線程數大於最大線程且當前已經超時爲獲取到且當前允許超時退出,則減少線程數量,成功後直接返回,失敗後重試
return null;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)//如果線程池運行狀態變化則重新執行外層循環,外層循環會做狀態判斷,因爲CAS失敗可能是線程池數量發生變化,則繼續內存循環重試
continue retry;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();//如果允許超時方式獲取,則用poll,否則使用take方法,從任務隊列中獲取任務
if (r != null)//獲取到任務則直接返回該任務,否則設置timedOut標記爲已經超時沒獲取到
return r;
timedOut = true;//設置timedOut標記爲已經超時沒獲取到,然後重新執行外層和內存循環,判斷狀態和是否超時退出Worker
} catch (InterruptedException retry) {
timedOut = false;//被中斷不認爲超時沒獲取到,有可能是線程池關閉,重新調用外層循環判斷獲取。
}
}
}
private void processWorkerExit(Worker w, boolean completedAbruptly) {//completedAbruptly爲true代表Worker因爲業務異常退出,false代表正常退出
if (completedAbruptly) //如果Worker是異常退出,則需要在此處將線程池數量減一。正常退出則會在getTask方法減少線程數量
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//獲取主鎖
try {
completedTaskCount += w.completedTasks;//將退出的線程完成過的任務計數加到線程池總完成任務計數上
workers.remove(w);//從工作線程集合中移除該工作線程
} finally {
mainLock.unlock();//釋放鎖
}
tryTerminate();//嘗試終止線程池,因爲這個Worker可能是當前線程池中最後一個Worker,tryTerminate方法在所有可能終止當前線程的地方被調用
int c = ctl.get();
if (runStateLessThan(c, STOP)) {//如果線程池沒有停止
if (!completedAbruptly) {//如果Worker是正常退出
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;//如果允許核心線程超時退出,則線程池最小線程數可以爲0,否則最小線程數爲corePoolSize
if (min == 0 && ! workQueue.isEmpty())//如果最小線程爲0且任務隊列不爲空,則至少保證池中有一個線程可以處理任務隊列中的任務
min = 1;
if (workerCountOf(c) >= min)//如果線程池中的線程數大於等於最小線程,則什麼都不做,否則創建工作線程。此處爲了工作線程正常退出時,保證池中至少存有核心線程數量的線程
return;
}
addWorker(null, false);//創建一個工作線程。正常退出時是爲了保證池中至少存有核心線程數量的線程;異常退出則直接重新補充一個工作線程。
}
}
ThreadPoolExecutor核心方法execute()方法源碼分析
public void execute(Runnable command)
在將來某個時間執行給定任務。該方法直接返回不等待任務執行完成,異步處理任務。
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);//移除成功則調用handler做線程池飽和的相應處理
else if (workerCountOf(recheck) == 0)//如果線程池線程數量是0,則添加一個空的非核心工作線程
addWorker(null, false);
}
else if (!addWorker(command, false))//如果添加隊列失敗或者不在運行中,說明任務隊列已滿,則添加非核心線程,添加失敗則調用handler做線程池飽和的相應處理
reject(command);//調用handler做線程池飽和的相應處理
}
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()))//表示ctl狀態爲RUNNING狀態或者爲SHUTDOWN狀態且此時任務隊列仍有任務未執行完時,可以繼續調用addWorker添加工作線程,但不能新建任務,即firstTask參數必須爲null.否則這裏將返回false,即新建工作線程失敗。
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))//如果當前線程數量超過最大容許CAPACITY,或者核心線程超出corePoolSize,或者非核心線程超出maximumPoolSize,都返回失敗。
return false;
if (compareAndIncrementWorkerCount(c))//原子自增一次計數器,自增成功代表線程數量增加,後續將創建線程。成功則直接跳出循環,否則重試直到返回
break retry;//自增成功則跳出循環
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)//自增失敗則重新讀取線程狀態,如果線程狀態和進入時發生變化,則也跳出循環。
continue retry;
}
}
boolean workerStarted = false;//工作線程是否啓動
boolean workerAdded = false;//工作線程是否成功添加
Worker w = null;
try {
final ReentrantLock mainLock = this.mainLock;
w = new Worker(firstTask);//創建一個工作線程管理者Worker,裏面會初始化一個線程,初始化的時候會附帶第一個啓動後將要執行的任務
final Thread t = w.thread;//獲取Worker管理的線程
if (t != null) {
mainLock.lock();//首先獲取主鎖
try {
int c = ctl.get();
int rs = runStateOf(c);
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {//校驗線程池狀態,運行中,或者SHUTDOWN且沒有任務(這個時候還新建Worker是爲了處理任務隊列中可能還存在的任務)
if (t.isAlive()) //校驗任務沒有被提前啓動,已經提前啓動則拋出異常
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;//設置標記爲啓動工作線程成功,至此爲止一個worker正式被添加進入workers數組並且正式開始運轉
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);//啓動失敗則移除該工作線程
}
return workerStarted;//創建並添加,並啓動工作線程成功纔算完全成功。
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException
執行給定的任務,當所有任務完成或超時期滿時(無論哪個首先發生),返回保持任務狀態和結果的 Future 列表。返回列表的所有元素的 Future.isDone() 爲 true。一旦返回後,即取消尚未完成的任務。注意,可以正常地或通過拋出異常來終止已完成的任務。如果此操作正在進行時修改了給定的 collection,則此方法的結果是不確定的。
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException {
if (tasks == null || unit == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);//總超時時間
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));//將所有任務包裝成一個個Future,順序和tasks中任務順序一致
long lastTime = System.nanoTime();
Iterator<Future<T>> it = futures.iterator();
while (it.hasNext()) {//執行所有任務
execute((Runnable)(it.next()));
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
if (nanos <= 0)
return futures;
}
for (Future<T> f : futures) {//循環獲取任務結果,是爲了檢測是否任務能在nanos納秒內執行完成。如果有任務超時沒有完成,則會在finally中取消所有能夠取消的未完成任務
if (!f.isDone()) {
if (nanos <= 0)
return futures;
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
long now = System.nanoTime();
nanos -= now - lastTime;
lastTime = now;
}
}
done = true;//正常完成所有任務
return futures;
} finally {
if (!done)//如果沒有完成則取消所有能夠取消的未完成任務,已經完成的任務不會被取消。保證返回的futures集合都能夠直接從Future.get()方法立即返回結果(正常或異常結果)。
for (Future<T> f : futures)
f.cancel(true);
}
}
ThreadPoolExecutor關閉
public void shutdown()
關閉線程池,仍會處理任務隊列中的任務,但是不接受新任務。如果已經關閉,則調用沒有其他作用。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();//校驗是否有執行shutdown的權限
advanceRunState(SHUTDOWN);//將ctl狀態置爲SHUTDOWN
interruptIdleWorkers();//關閉尚未獲得task對象的worker(即還未執行到getTask()方法或者還未得到getTask()返回的worker
onShutdown(); //鉤子方法,用戶可以在這裏處理自定義邏輯。
} finally {
mainLock.unlock();
}
tryTerminate();//嘗試終止線程池。
}
private void interruptIdleWorkers() {//中斷空閒的Worker
interruptIdleWorkers(false);
}
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//獲取主鎖
try {
for (Worker w : workers) {//遍歷所有workers
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {//如果當前Worker線程沒有被中斷,且嘗試獲取鎖成功(代表任務沒有在線程執行中)
try {
t.interrupt();//中斷該線程
} catch (SecurityException ignore) {
} finally {
w.unlock();//解鎖Worker
}
}
if (onlyOne)//true代表只中斷第一個空閒的Worker
break;
}
} finally {
mainLock.unlock();//解鎖主鎖
}
}
final void tryTerminate() {
for (;;) {
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))//線程池運行中或者已經終止,或者SHUTDOWN且任務隊列不爲空,直接返回(SHUTDOWN且任務隊列不爲空時,會在Worker退出時調用tryTerminate方法終止線程池)
return;
if (workerCountOf(c) != 0) { //工作線程不爲0則中斷一個工作線程,直接返回。(STOP時,任務正在運行中,運行完成後,會在Worker退出時調用tryTerminate方法終止線程池)
interruptIdleWorkers(ONLY_ONE);
return;
}
//ctl狀態爲STOP,或者爲SHUTDOWN且任務隊列爲空,並且工作線程爲0,才繼續執行
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();//獲取主鎖
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {//將狀態設置爲TIDYING,執行到這一步意味着工作線程爲0,任務隊列空,狀態爲STOP或SHUTDOWN。
try {
terminated();//線程池擴展點,終止線程池時執行
} finally {
ctl.set(ctlOf(TERMINATED, 0));//執行完terminated後將狀態設置爲TERMINATED
termination.signalAll();//喚醒等待在awaitTermination方法上的線程,awaitTermination是等待線程池終止的方法,阻塞直到線程池終止或者超時,中斷
}
return;//退出,否則將會for循環重試
}
} finally {
mainLock.unlock();//獲取主鎖
}
}
}
public List<Runnable>
shutdownNow()
嘗試停止所有的活動執行任務、停止任務隊列的處理,並返回等待執行的任務列表。並不保證能夠停止正在處理的活動執行任務,但是會盡力嘗試。 此實現通過 Thread.interrupt() 取消任務,所以無法響應中斷的任何任務可能永遠無法終止。
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
interruptIdleWorkers();//關閉尚未獲得task對象的
checkShutdownAccess();//校驗是否有執行
advanceRunState(STOP);//將ctl狀態置爲STOP
interruptWorkers();//關閉所有啓動了的的worker,中斷所有worker的線程
tasks = drainQueue();//清空任務隊列並返回未執行的任務列表
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;//返回未執行的任務列表
}
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
List<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList);//將workQueue中的任務轉移到taskList返回
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
ThreadPoolExecutor擴展點
ThreadPoolExecutor提供了幾個protected的方法,在任務執行前,執行後,和線程池終止時執行。可以在自定義線程池中自由實現,用來記錄和監控線程池的運行情況。
protected void beforeExecute(Thread t, Runnable r) { }//在執行給定線程中的給定 Runnable 之前調用的方法。
protected void afterExecute(Runnable r, Throwable t) { }//基於完成執行給定 Runnable 所調用的方法。
protected void terminated() { }//當 Executor 已經終止時調用的方法。