一. 爲什麼使用線程池?
- a.線程創建所需時間爲T1,線程執行任務時間爲T2,線程銷燬時間爲T3,而往往T1+T3>T2。所以頻繁創建線程會損壞而外的時間。
- b.如果有任務來了,再去創建線程的話效率比較低。
- c.線程池可以管理控制線程,線程是稀缺資源,如果無休止的創建會消耗系統資源,還會降低系統穩定性。使用線程池可以進行統一分配,方便調優和監控,重複利用。
- d.線程池提供隊列,存放緩衝等待執行任務。
二. 有多少種線程池?
Java通過Executors提供四種線程池,分別爲:
- newCachedThreadPool:創建一個可緩存線程池,如果線程池長度超過處理需要,可靈活回收空閒線程,若無可回收,則新建線程。
- newFixedThreadPool :創建一個定長線程池,可控制線程最大併發數,超出的線程會在隊列中等待。
- newScheduledThreadPool :創建一個定長線程池,支持定時及週期性任務執行。
- newSingleThreadExecutor :創建一個單線程化的線程池,它只會用唯一的工作線程來執行任務,保證所有任務按照指定順序(FIFO, LIFO, 優先級)執行。
三. 線程池執行器的構造方法
/**
* 使用給定的初始參數創建新ThreadPoolExecutor
*
* @param corePoolSize 保留在池中的線程數,即使它們是空閒的,除非設置了allowCoreThreadTimeOut
* @param maximumPoolSize 池中允許的最大線程數
* @param keepAliveTime 當線程數量大於核心時,這是多餘空閒線程在終止前等待新任務的最大時間。
* @param unit keepAliveTime參數的時間單位
* @param workQueue 在執行任務之前用於保存任務的隊列。此隊列將只保存由execute方法提交的可運行任務。
* @param threadFactory 執行器創建新線程時使用的工廠
* 默認爲DefaultThreadFactory, Thread newThread(Runnable r) 創建新的線程。
* @param handler 當執行被阻塞時使用的處理程序,因爲線程邊界和隊列容量已經達到
默認 AbortPolicy 總是拋出rejectedExecution。
* @throws IllegalArgumentException 以下任意條件滿足,拋出IllegalArgumentException
* corePoolSize < 0
* keepAliveTime < 0
* maximumPoolSize <= 0
* maximumPoolSize < corePoolSize
* @throws NullPointerException 如果 workQueue or threadFactory or handler is null
*/
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
四. 線程池的使用
@Slf4j
public class ThreadPoolExample {
public static void main(String[] args) {
ArrayBlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(6);
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 3000, TimeUnit.MILLISECONDS, blockingQueue, new RejectedExecutionHandler() {
@Override
public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
log.info("執行拒絕策略: corePoolSize :{},maxPoolSize:{},queue size : {} ", executor.getCorePoolSize(), executor.getMaximumPoolSize(), executor.getQueue().size());
}
});
AtomicInteger atomicInteger = new AtomicInteger();
for (int i = 0; i < 20; i++) {
executor.execute(() -> {
System.out.println(executor.getCorePoolSize() + "-" + executor.getPoolSize() + "-" + executor.getQueue().size());
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
}
打印輸出:
5-2-0
5-2-0
5-4-0
5-5-0
5-5-1
5-6-6
5-8-6
5-9-6
5-9-6
5-10-6
5-10-5
5-10-3
5-10-4
5-10-2
5-10-1
5-10-0
執行拒絕策略: corePoolSize :5,maxPoolSize:10,queue size : 6
5-10-1
5-10-0
5-10-1
1. 流程圖
2. 主要方法分析
1. execute(Runnable runnable); 執行任務
public void execute(Runnable command) {
//需要執行的任務command爲空,拋出空指針異常
if (command == null)
throw new NullPointerException();
/*
*執行的流程實際上分爲三步
*1、如果運行的線程小於corePoolSize,以用戶給定的Runable對象新開一個線程去執行
* 並且執行addWorker方法會以原子性操作去檢查runState和workerCount,以防止當返回false的
* 時候添加了不應該添加的線程
*2、 如果任務能夠成功添加到隊列當中,我們仍需要對添加的線程進行雙重檢查,有可能添加的線程在前
* 一次檢查時已經死亡,又或者在進入該方法的時候線程池關閉了。所以我們需要複查狀態,並有有必
* 要的話需要在停止時回滾入列操作,或者在沒有線程的時候新開一個線程
*3、如果任務無法入列,那我們需要嘗試新增一個線程,如果新建線程失敗了,我們就知道線程可能關閉了
* 或者飽和了,就需要拒絕這個任務
*
*/
//獲取線程池的狀態
int c = ctl.get();
//工作線程 < corePoolSize
if (workerCountOf(c) < corePoolSize) {
//處於運行狀態的線程數小於核心線程數,添加任務到worker集合當中
//添加核心任務,如果成功,方法結束
if (addWorker(command, true))
//成功返回
return;
//失敗的話再次獲取線程池的狀態
c = ctl.get();
}
//工作線程 >= corePoolSize 時,如果線程池處於運行狀態,將任務加入到阻塞隊列中
if (isRunning(c) && workQueue.offer(command)) {
//再次獲取線程池的狀態
int recheck = ctl.get();
//再次檢查狀態
//如果線程池不處於RUNNING狀態,將任務從workQueue隊列中移除,並且拒絕任務
if (! isRunning(recheck) && remove(command))
reject(command);
//如果線程池處於RUNNING,此時線程池的工作線程個數爲0,加入新的非核心任務
else if (workerCountOf(recheck) == 0)
//添加非核心的worker 爲null 此處目的:避免堵塞隊列的任務沒有工作線程去執行。
addWorker(null, false);
}
//隊列添加失敗的話(滿了),就添加到非核心任務
else if (!addWorker(command, false))
//添加到非核心任務失敗,可能是大於最大線程數導致
reject(command);
}
2. reject(Runnable) 拒絕任務
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
就是調用handler.rejectedExecution(command, this); 由具體的拒絕策略實現。
3. addWorker(Runnable firstTask, boolean core) 添加工作線程
private boolean addWorker(Runnable firstTask, boolean core) {
//外部循環標記
retry:
//外層死循環
for (;;) {
//獲取線程池控制狀態
int c = ctl.get();
//獲取 線程池的運行狀態
int rs = runStateOf(c);
/**
* 1. 狀態爲SHUTDOWN,進來的任務爲空,但堵塞隊列不是空 這種情況下,還是要繼續執行的
* 2. 線程池runState至少已經是SHUTDOWN,且不滿足條件1,直接返回false
*/
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
//內層死循環
for (;;) {
//獲取線程池的線程個數
int wc = workerCountOf(c);
// 如果是核心的 線程個數大於核心數就不添加
//如果非核心,線程個數大於最大線程池數量就不添加
//返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//增加workerCount +1 (原子操作)
if (compareAndIncrementWorkerCount(c))
// 如果增加成功,跳出循環,進行下面的創建Worker執行任務
break retry;
c = ctl.get(); // 失敗重新獲取線程池ctl
// 判斷當前runState與最開始rs是否相等,不相等說明狀態已經被修改,返回重新執行
if (runStateOf(c) != rs)
continue retry;
}
}
//標誌 工作線程是否已開始
boolean workerStarted = false;
//標誌 工作線程新建是否已完成
boolean workerAdded = false;
Worker w = null;
try {
// 根據firstTask創建Worker開始執行任務
w = new Worker(firstTask);
//注意: thread 和 firstTask是不同的,thread是threadFatory new出來的
final Thread t = w.thread;
if (t != null) {
// 使用重入鎖的目的是因爲workers使用的是 HashSet線程不安全
final ReentrantLock mainLock = this.mainLock;
// 加鎖
mainLock.lock();
try {
//持有鎖時重新檢查。在ThreadFactory失敗或獲取鎖之前關閉時退出。
int rs = runStateOf(ctl.get());
//如果線程池狀態爲RUNNING,或者(線程狀態爲SHUTDOWN且傳進來的任務爲null)
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 因爲要加入這個任務,所以判斷創建的線程是否存活,存活表示此線程已經在運行,不是新的線程,存活則拋出異常
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 加入工作workers中,workers中包含線程池中所有的工作線程,只有持有鎖時才能訪問
workers.add(w);
// 獲取當前工作線程數
int s = workers.size();
// 如果大於最大線程數,將最大線程數重新賦值
if (s > largestPoolSize)
largestPoolSize = s;
// worker的添加工作狀態改爲true
workerAdded = true;
}
} finally {
// 釋放鎖
mainLock.unlock();
}
// 如果添加worker工作完成,啓動線程,並修改線程啓動狀態
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
// //判斷線程有沒有啓動成功,沒有則調用addWorkerFailed方法
if (! workerStarted)
// 將線程從workers中刪除,該方法中也是用了重入鎖,保證線程安全,嘗試終止
addWorkerFailed(w);
}
// 返回線程啓動狀態
return workerStarted;
}
4. Worker.run()
//3.addWorker方法中,workerAdded爲true, 調用了start();
public void run() {
runWorker(this);
}
5. runWorker(Worker w); 運行工作線程
final void runWorker(Worker w) {
//獲取當前線程
Thread wt = Thread.currentThread();
//獲取worker裏的任務
Runnable task = w.firstTask;
//將worker實例的任務賦值爲null
w.firstTask = null;
/*
*unlock方法會調用AQS的release方法
*release方法會調用具體實現類也就是Worker的tryRelease方法
*也就是將AQS狀態置爲0,允許中斷
*/
w.unlock(); // allow interrupts
//是否突然完成
boolean completedAbruptly = true;
try {
//每個worker實例的task不爲空,或者通過getTask獲取的不爲空(從阻塞隊列中take一個) 循環執行
while (task != null || (task = getTask()) != null) {
//獲取鎖
w.lock();
/*獲取線程池的控制狀態,至少要大於STOP狀態
*如果狀態不對,檢查當前線程是否中斷並清除中斷狀態,並且再次檢查線程池狀態是否大於STOP
*如果上述滿足,檢查該對象是否處於中斷狀態,不清除中斷標記
*/
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
//中斷對象
wt.interrupt();
try {
//執行前的方法,由子類具體實現
beforeExecute(wt, task);
Throwable thrown = null;
try {
//執行任務 也就是execute傳遞過來的runnable對象,調用run方法
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
task = null;
//已完成任務數+1
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
//處理並退出當前worker
processWorkerExit(w, completedAbruptly);
}
}
五. 源碼
package java.util.concurrent;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.*;
/**
* ThreadPoolExecutor 線程池
* @since 1.5
* @author Doug Lea
*/
public class ThreadPoolExecutor extends AbstractExecutorService {
/**
* 用來標記線程池狀態(高3位),線程個數(低29位)
* RUNNING -> (高3位):11100000000000000000000000000000
* ctl = 11100000000000000000000000000000|0 = 11100000000000000000000000000000
* 默認是RUNNING狀態,線程個數爲0
*/
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
/**
*線程個數掩碼位數,並不是所有平臺int類型是32位,所以準確說是具體平臺下Integer的二進制位數-3後的剩餘位數纔是線程的個數
*/
private static final int COUNT_BITS = Integer.SIZE - 3;
//線程最大個數(低29位)00011111111111111111111111111111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
/**
*高3位表示線程池的狀態,低29位表示線程池的工作線程數量
*線程池狀態轉換:
1.RUNNING -> SHUTDOWN:顯式調用 shutdown() 方法,或者隱式調用了 finalize(),它裏面調用了 shutdown() 方法。
2.RUNNING or SHUTDOWN -> STOP:顯式調用 shutdownNow() 方法時候。
3.SHUTDOWN -> TIDYING:當線程池和任務隊列都爲空的時候。
4.STOP -> TIDYING:當線程池爲空的時候。
5.TIDYING -> TERMINATED:當 terminated() hook 方法執行完成時候。
*/
// runState is stored in the high-order bits
// (高3位):11100000000000000000000000000000
// 接受新任務並且處理阻塞隊列裏的任務;
private static final int RUNNING = -1 << COUNT_BITS;
// (高3位):00000000000000000000000000000000
// 拒絕新任務但是處理阻塞隊列裏的任務;
private static final int SHUTDOWN = 0 << COUNT_BITS;
// (高3位):00100000000000000000000000000000
// 拒絕新任務並且拋棄阻塞隊列裏的任務,同時會中斷正在處理的任務;
private static final int STOP = 1 << COUNT_BITS;
// (高3位):01000000000000000000000000000000
// 所有任務都執行完(包含阻塞隊列裏面任務)當前線程池活動線程爲 0,將要調用 terminated 方法;
private static final int TIDYING = 2 << COUNT_BITS;
// (高3位):01100000000000000000000000000000
// 終止狀態,terminated方法調用完成以後的狀態。
private static final int TERMINATED = 3 << COUNT_BITS;
// Packing and unpacking ctl
//獲取高三位 運行狀態 CAPACITY:00011111111111111111111111111111 ~CAPACITY: 11100000000000000000000000000
//c & 11100000000000000000000000000 -> XXX0000000000000000000000000000000 也是就c的高三位運行狀態
private static int runStateOf(int c) { return c & ~CAPACITY; }
//獲取低29位 線程個數 CAPACITY:00011111111111111111111111111111
//
private static int workerCountOf(int c) { return c & CAPACITY; }
//計算ctl新值,線程狀態 與 線程個數
//首先線程狀態rs 低29位都是0 wc 線程個數:高3位都是0 所以ctlOf 得到的是rs的高三位wc線程個數的低29位
private static int ctlOf(int rs, int wc) { return rs | wc; }
/*
* 由於任務線程計數器不會爲負數,所以比較狀態時,就不必要解包ctl
* 第一個狀態是否<第二個狀態
*/
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
//第一個狀態是否>=第二個狀態
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
// 判斷這個狀態是否在運行 也就是狀態小於SHUTDOWN ? 這裏爲什麼不用=RUNNING?
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
/**
* 初始化的時候,低29位都是0 ,並且線程池的容量 (1<< 29)-1 嘗試CAS 任務線程數+1
*/
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
/**
* 嘗試CAS任務線程數-1
*/
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
/**
* 在任務線程中斷結束時,調用processWorkerExit方法,用於清除當前中斷任務線程計數,在getTask也有用到。
*/
private void decrementWorkerCount() {
//無限循環調用清除所有的任務線程數,直到此操作CAS成功執行。
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
/**
* 任務隊列用於放提交到線程池的任務,並有任務線程處理。我們一般不用
poll返回null來判斷隊列是否爲null,而是用isEmpty方法判斷隊列是否爲空,
以便判斷是否應該將線程池狀態從SHUTDOWN切換到TIDYING。但是強烈建議在用
DelayQueues作爲任務隊列時可以用poll,由於poll的方法允許返回null,即使
在延時時間過期時,返回爲非null。
*/
private final BlockingQueue<Runnable> workQueue;
/**
* 當需要訪問任務線程集合和相關的記錄需要,加鎖。當我們用一個併發集合
排序時,一般情況下,最好使用鎖。其中有一個原因爲interruptIdleWorkers,
即中斷空閒任務線程,這樣可以在關閉線程池的過程中,避免中斷風暴。
否則退出的任務線程將會併發中斷還沒有中斷的任務線程,即有可能發生中斷風暴。
也被用於簡單的統計largestPoolSize等。在關閉和立即關閉時,我們需要持有鎖,
以便在獨立檢查中斷允許和實際中斷狀態時,保證任務線程集的穩定性。
*/
private final ReentrantLock mainLock = new ReentrantLock();
/**
* 線程池任務線程集,當持有mainLock鎖時,可以訪問線程池任務線程集
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
* 等待線程池結束條件 後面的纔會執行
*/
private final Condition termination = mainLock.newCondition();
/**
* 在持有mainLock的情況下,追蹤最大線程池
*/
private int largestPoolSize;
/**
* 在持有mainLock的情況下,可以訪問,completedTaskCount爲完成任務計數器,
在任務線程結束時,更新。
*/
private long completedTaskCount;
/*
* 所有用於控制參數被修飾爲volatiles,以便正在進行的操作,都是基於最新值,
在不需要鎖的情況下,相對於其他動作,依賴於這些參數的可變量同步地改變。
即所有需要引用這些參數的變量或動作,可以立即看到參數最新值。
*/
/**
* ThreadFactory爲創建任務線程的工廠。所有任務線程的創建都是在調用addWorker
的過程中,使用線程工廠創建。所有調用線程工廠創建任務線程的使用者,必要
做好添加任務線程失敗的心理準備,這也許會影響系統或用戶的線程數量限制策略。
即使不作爲錯誤對待,創建任務線程失敗,也許導致新任務被拒絕,或一個任務
阻塞在任務隊列中。
*
* 即使在創建任務線程是可能會有OutOfMemoryError的錯誤,我們必須儘量保證
線程池的不變性。這種事情的發生,一般是由在我們創建一個線程的本地棧時,
用戶想要關閉線程池,清除任務線程。在沒有遇到OutOfMemoryError的情況下,
將會有足夠的內存用於清理工作。
*/
private volatile ThreadFactory threadFactory;
/**
* 當線程池飽和或線程池關閉時,拒絕任務處理handler 拒絕策略
*/
private volatile RejectedExecutionHandler handler;
/**
* 線程池空閒任務線程,等待任務的時間。如果當前線程數量大於核心線程池數量,
且allowCoreThreadTimeOut爲true,任務線程空閒,允許等待keepAliveTime時間,
以便在這個時間範圍內,有任務需要執行
*/
private volatile long keepAliveTime;
/**
* 在當前線程數量大於核心線程池數量的情況下,是否允許空閒任務線程等,
保活keepAliveTime時間,等待任務的到來。
*/
private volatile boolean allowCoreThreadTimeOut;
/**
* 在不允許空閒等待的情況,核心線程池數量,即保活的任務線程最小數量。
如果允許空閒等待,線程池任務線程可能爲0。
*/
private volatile int corePoolSize;
/**
* 最大線程池數量,如果容量是有界的,實際爲CAPACITY
*/
private volatile int maximumPoolSize;
/**
* 默認的拒絕任務策略,拋出運行時異常
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
/**
* 當調用者調用shutdown和shutdownNow方法時,需要shutdownPerm運行時允許權限,
以便調用者可以權限中斷任務線程,在關閉的時候,首先檢查調用者是否有
shutdownPerm運行時權限。通過ThreadGroup.checkAccess是否擁有權限。
*
* 實際上調用線程中斷(interruptIdleWorkers和interruptWorkers)
忽略SecurityExceptions,意味着嘗試中斷默認失敗。在線程關閉的時候,
除非SecurityManager有不一致的策略(有事允許,有時不允許),否則中斷不應該失敗。
如果SecurityManager爲不一致的策略,線程的中斷實際上有可能失敗。
*/
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
/* 執行終結器finalizer時要使用的上下文,或爲空 */
private final AccessControlContext acc;
/**
* 類Worker主要維護運行任務的線程的中斷控制狀態,以及其他次要的記帳。該類機會性地擴展了AbstractQueuedSynchronizer,以簡化獲取和釋放圍繞每個任務執行的鎖的過程。
* 這可以防止旨在喚醒等待任務的工作線程而不是中斷正在運行的任務的中斷。我們實現了一個簡單的不可重入互斥鎖,而不是使用ReentrantLock,因爲我們不希望工作任務在調用setCorePoolSize之類的池控制方法時能夠重新獲取鎖。
* 另外,爲了在線程真正開始運行任務之前禁止中斷,我們將鎖狀態初始化爲負值,並在啓動時清除它(在runWorker中)。
*/
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
*這個類永遠不會被序列化,但是我們提供了一個serialVersionUID來禁止javac警告。
*/
private static final long serialVersionUID = 6138294804551838833L;
/** 此工作線程正在運行。如果工廠失敗,則爲空。 */
final Thread thread;
/** 要運行的初始任務。可能爲空。 */
Runnable firstTask;
/** 記錄該線程完成了多少個任務(非整個線程池)。 */
volatile long completedTasks;
/**
* 使用給定的第一個任務和ThreadFactory中的線程創建。
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // 禁止中斷runWorker
this.firstTask = firstTask;
//ThreadFacotry.newThread(Runnable)
this.thread = getThreadFactory().newThread(this);
}
/** 將主運行委託給外部的線程池對象處理 */
public void run() {
runWorker(this);
}
// 是否獨有
// 值0表示未鎖定狀態。值1表示鎖定狀態。
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
//嘗試以獨佔模式獲取。此方法應查詢對象的狀態是否允許以獨佔模式獲取它,如果允許則獲取它。
protected boolean tryAcquire(int unused) {
//獲取worker 的 stateOffset狀態偏移量的值是否是0,如果是0,更新爲1
if (compareAndSetState(0, 1)) {
//設置當前擁有獨佔訪問權限的線程。null 參數表示沒有線程擁有訪問權限。此方法不會強制任何同步或volatile字段訪問。
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
//嘗試釋放
protected boolean tryRelease(int unused) {
//設置沒有任何線程擁有獨佔訪問權限
setExclusiveOwnerThread(null);
//設置狀態爲0
setState(0);
return true;
}
//加鎖
public void lock() { acquire(1); }
//嘗試獲取鎖
public boolean tryLock() { return tryAcquire(1); }
//解鎖
public void unlock() { release(1); }
//判斷是否鎖定 ,isHeldExclusively()是否被獨享
public boolean isLocked() { return isHeldExclusively(); }
//,中斷此線程
void interruptIfStarted() {
Thread t;
//當狀態>=0的時候 線程不爲空,且沒有被中斷
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
/*
* 控制狀態設置方法
*/
/**
* 從運行的狀態過渡到targetState
* 如果當前已經大於了targetState,就什麼都不做。
將運行狀態轉換爲給定目標,或者如果已經至少是給定目標,則將其單獨保留。
targetState參數的使用值只有兩個:SHUTDOWN與STOP
SHUTDOWN值爲0
STOP值爲1<<29 = 2^29。 二進制表示的話1後面29個0
假設傳的參數是SHUTDOWN:
ctlOf(targetState, workerCountOf(c)) = workerCountOf(c) > 0,一般就是線程池的個數
假設傳的參數是STOP: 2^29
ctlOf(targetState, workerCountOf(c)) = 2^29 + 2 , 爲STOP狀態
*/
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();//當前運行狀態
//如果當前狀態已經至少是目標狀態 或者 將當前狀態改成目標狀態並且記錄總worker數量成功 結束死循環
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
/**
* 在以下情況將線程池變爲TERMINATED終止狀態
* shutdown 且 正在運行的worker 和 workQueue隊列 都empty
* stop 且 沒有正在運行的worker
*
* 這個方法必須在任何可能導致線程池終止的情況下被調用,如:
* 減少worker數量
* shutdown時從queue中移除任務
*
* 這個方法不是私有的,所以允許子類ScheduledThreadPoolExecutor調用
*/
final void tryTerminate() {
//這個for循環主要是和進入關閉線程池操作的CAS判斷結合使用的
for (;;) {
/**
* 線程池是否需要終止
* 如果以下3中情況任一爲true,return,不進行終止
* 1、還在運行狀態
* 2、狀態是TIDYING、或 TERMINATED,已經終止過了
* 3、SHUTDOWN 且 workQueue不爲空
*/
int c = ctl.get(); //狀態
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
/**
* 只有shutdown狀態 且 workQueue爲空,或者 stop狀態能執行到這一步
* 如果此時線程池還有線程(正在運行任務,正在等待任務)
* 中斷喚醒一個正在等任務的空閒worker
* 喚醒後再次判斷線程池狀態,會return null,進入processWorkerExit()流程
*/
if (workerCountOf(c) != 0) { // 有資格終止
/**
* 在這種情況下,最多有一個worker被中斷,爲了傳播shutdown信號,以免所有的線程都在等待???
* 爲保證線程池最終能終止,這個操作總是中斷一個空閒worker
* 而shutdown()中斷所有空閒worker,來保證空閒線程及時退出
*
*/
interruptIdleWorkers(ONLY_ONE);
return;
}
/**
* 如果狀態是SHUTDOWN,workQueue也爲空了,正在運行的worker也沒有了,開始terminated
*/
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//CAS:將線程池的ctl變成TIDYING(所有的任務被終止,workCount爲0,爲此狀態時將會調用 //terminated()方法),期間ctl有變化就會失敗,會再次for循環
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));//將線程池的ctl變成TERMINATED
//Condition喚醒調用了 等待線程池終止的線程 awaitTermination()
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
// 如果上面的CAS判斷false,再次循環
}
}
/*
* 判斷調用者是否有權限shutdown線程池
*/
/**
* 如果有安全管理器,請確保調用方具有關閉線程的權限(請參閱shutdownPerm)。如果這通過了,另外還要確保允許調用方中斷每個工作線程。即使第一次檢查通過,如果SecurityManager特別處理一些線程,這也可能不是真的。
*/
private void checkShutdownAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
/**
* 中斷所有線程,包括正在運行的線程。忽略SecurityExceptions(在這種情況下,某些線程可能保持不間斷)
*/
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
/**
其中會判斷worker的AQS state是否大於0,即worker是否已經開始運作,再調用Thread.interrupt()需要注意的是,對於運行中的線程調用Thread.interrupt()並不能保證線程被終止,task.run()內部可能捕獲了InterruptException,沒有上拋,導致線程一直無法結束
*/
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
/**
* 中斷在等待任務的線程(沒有上鎖的空閒線程),中斷喚醒後,可以判斷線程池狀態是否變化來決定是否繼續
*
* onlyOne如果爲true,最多interrupt一個worker
* 只有當終止流程已經開始,但線程池還有worker線程時,tryTerminate()方法會做調用onlyOne爲true的調用
* (終止流程已經開始指的是:shutdown狀態 且 workQueue爲空,或者 stop狀態)
* 在這種情況下,最多有一個worker被中斷,爲了傳播shutdown信號,以免所有的線程都在等待
* 爲保證線程池最終能終止,這個操作總是中斷一個空閒worker
* 而shutdown()中斷所有空閒worker,來保證空閒線程及時退出
*/
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
//1、線程是否已經被中斷,是就什麼都不做
//2、worker.tryLock() 是否成功
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
/**
* 常見形式的interruptedleworkers,以避免記住布爾參數的含義。
*/
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
private static final boolean ONLY_ONE = true;
/*
* Misc utilities, most of which are also exported to
* ScheduledThreadPoolExecutor
*/
/**
* 爲給定的命令調用被拒絕的執行處理程序。受保護的包供ScheduledThreadPoolExecutor使用。
*/
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
/**
* 在調用shutdown時執行運行狀態轉換之後的任何進一步清理。這裏是no操作,但ScheduledThreadPoolExecutor用於取消延遲的任務。
*/
void onShutdown() {
}
/**
* ScheduledThreadPoolExecutor在關閉期間啓用運行任務所需的狀態檢查。
*
* @param shutdownOK 如果 SHUTDOWN 則返回true
*/
final boolean isRunningOrShutdown(boolean shutdownOK) {
////獲取高三位 運行狀態
int rs = runStateOf(ctl.get());
// RUNNING狀態或(線程池處於SHUTDOWN狀態並且參數shutdownOK爲true),返回true
return rs == RUNNING || (rs == SHUTDOWN && shutdownOK);
}
/**
* 調用隊列的drainTo一次當前隊列的元素到taskList,
* 可能失敗,如果調用drainTo後隊列海不爲空,則循環刪除,並添加到taskList
*/
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
//一次性從BlockingQueue獲取所有可用的數據對象(還可以指定獲取數據的個數),通過該方法, //可以提升獲取數據效率;不需要多次分批加鎖或釋放鎖。
q.drainTo(taskList);
if (!q.isEmpty()) {
for (Runnable r : q.toArray(new Runnable[0])) {
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
/*
* Methods for creating, running and cleaning up after workers
*/
/**
* 添加worker 第一個任務 ; 是否核心
*/
private boolean addWorker(Runnable firstTask, boolean core) {
//外部循環標記
retry:
//外層死循環
for (;;) {
//獲取線程池控制狀態
int c = ctl.get();
//獲取 線程池的運行狀態
int rs = runStateOf(c);
// 僅在必要時檢查隊列是否爲空。
/**
*1.如果線程池runState至少已經是SHUTDOWN
*2. 有一個是false則addWorker失敗,看false的情況
* - runState==SHUTDOWN,即狀態已經大於SHUTDOWN了
* - firstTask爲null,即傳進來的任務爲空,結合上面就是runState是SHUTDOWN,但是
* firstTask不爲空,代表線程池已經關閉了還在傳任務進來
* - 隊列爲空,既然任務已經爲空,隊列爲空,就不需要往線程池添加任務了
*/
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
//內層死循環
for (;;) {
//獲取線程池的線程個數
int wc = workerCountOf(c);
// 如果是核心的 線程個數大於核心數就不添加
//如果非核心,線程個數大於最大線程池數量就不添加
//返回false
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//增加workerCount +1 (原子操作)
if (compareAndIncrementWorkerCount(c))
// 如果增加成功,則直接返回
break retry;
c = ctl.get(); // 失敗重新獲取線程池ctl
// 判斷當前runState與最開始rs是否相等,不相等說明狀態已經被修改,返回重新執行
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 {
// 根據firstTask創建Worker開始執行任務
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
// 使用重入鎖的目的是因爲workers使用的是 HashSet線程不安全
final ReentrantLock mainLock = this.mainLock;
// 加鎖
mainLock.lock();
try {
//持有鎖時重新檢查。在ThreadFactory失敗或獲取鎖之前關閉時退出。
int rs = runStateOf(ctl.get());
// rs < SHUTDOWN 說明線程池正在處於運行狀態,rs =SHUTDOWN firstTask //爲空,其中firstTask 爲空表示只是新建線程但沒有任務需要執行
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
// 因爲要加入這個任務,所以判斷創建的線程是否存活,存活表示此線程已經在運行,不是新的線程,存活則拋出異常
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
// 加入worker中,workers中包含線程池中所有的工作線程,只有持有鎖時才能訪問
workers.add(w);
// 獲取當前工作線程數
int s = workers.size();
// 如果大於最大線程數,將最大線程數重新賦值
if (s > largestPoolSize)
largestPoolSize = s;
// worker的添加工作狀態改爲true
workerAdded = true;
}
} finally {
// 釋放鎖
mainLock.unlock();
}
// 如果添加worker工作完成,啓動線程,並修改線程啓動狀態
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
// //判斷線程有沒有啓動成功,沒有則調用addWorkerFailed方法
if (! workerStarted)
// 將線程從workers中刪除,該方法中也是用了重入鎖,保證線程安全
addWorkerFailed(w);
}
// 返回線程啓動狀態
return workerStarted;
}
/**
* addWorker方法添加worker失敗,並且沒有成功啓動任務的時候,就會調用此方法,將任務從workers中移除,並 * 且workerCount做-1操作。
*/
private void addWorkerFailed(Worker w) {
//重入鎖
final ReentrantLock mainLock = this.mainLock;
//獲取鎖
mainLock.lock();
try {
//如果worker不爲null
if (w != null)
//workers移除worker
workers.remove(w);
//通過CAS操作,workerCount-1
decrementWorkerCount();
//當對線程池執行了非正常成功邏輯的操作時,都會需要執行tryTerminate嘗試終止線程池
tryTerminate();
} finally {
//釋放鎖
mainLock.unlock();
}
}
/**
* 整個線程結束時調用,線程退出操作。統計整個線程池完成的任務個數之類的工作
*
* @param w the worker
* @param completedAbruptly if the worker died due to user exception
*/
private void processWorkerExit(Worker w, boolean completedAbruptly) {
/*
*completedAbruptly:在runWorker出現,代表是否突然完成的意思
*也就是在執行任務過程當中出現異常,就會突然完成,傳true
*
*如果是突然完成,需要通過CAS操作,workerCount-1
*不是突然完成,則不需要-1,因爲getTask方法當中已經-1
*
*下面的代碼註釋貌似與代碼意思相反了
*/
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
//生成重入鎖
final ReentrantLock mainLock = this.mainLock;
//獲取鎖
mainLock.lock();
try {
//線程池統計的完成任務數completedTaskCount加上worker當中完成的任務數
completedTaskCount += w.completedTasks;
//從HashSet<Worker>中移除
workers.remove(w);
} finally {
//釋放鎖
mainLock.unlock();
}
//因爲上述操作是釋放任務或線程,所以會判斷線程池狀態,嘗試終止線程池
tryTerminate();
//獲取線程池的控制狀態
int c = ctl.get();
//判斷runState是否小於STOP,即是RUNNING或者SHUTDOWN
//如果是RUNNING或者SHUTDOWN,代表沒有成功終止線程池
if (runStateLessThan(c, STOP)) {
/*
*是否突然完成
*如若不是,代表已經沒有任務可獲取完成,因爲getTask當中是while循環
*/
if (!completedAbruptly) {
/*
*allowCoreThreadTimeOut:是否允許core thread超時,默認false
*min-默認是corePoolSize
*/
//允許core thread超時並且隊列不爲空
//min爲0,即允許core thread超時,這樣就不需要維護核心核心線程池了
//如果workQueue不爲空,則至少保持一個線程存活
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
//如果workerCount大於min,則表示滿足所需,可以直接返回
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//關鍵這在這,加入一條firstTask爲null的非核心線程任務,替換當前線程
addWorker(null, false);
}
}
/**
* 只是在線程從工作隊列 poll 任務時,加上了超時限制,如果線程在 keepAliveTime 的時間內 poll 不到任務,那我就認爲這條線程沒事做,可以幹掉了
*/
private Runnable getTask() {
//標誌是否獲取任務超時
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
//獲取線程池的控制狀態
int c = ctl.get();
//獲取線程池的runState
int rs = runStateOf(c);
/*
*判斷線程池的狀態,出現以下兩種情況
*1、runState大於等於SHUTDOWN狀態
*2、runState大於等於STOP或者阻塞隊列爲空
*將會通過CAS操作,進行workerCount-1並返回null
*/
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
//獲取線程池的workerCount
int wc = workerCountOf(c);
/*
*allowCoreThreadTimeOut:是否允許core Thread超時,默認false
*workerCount是否大於核心線程數
* 此時timed 表示
*/
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
/*
*1、wc大於maximumPoolSize或者已超時
*2、隊列不爲空時保證至少有一個任務
*/
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
/*
*通過CAS操作,workerCount-1
*能進行-1操作,證明wc大於maximumPoolSize或者已經超時
*/
if (compareAndDecrementWorkerCount(c))
//-1操作成功,返回null
return null;
//-1操作失敗,繼續循環
continue;
}
try {
/*
*wc大於核心線程池
*執行poll方法
*小於核心線程池
*執行take方法
*/
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
//判斷任務不爲空返回任務
if (r != null)
return r;
//獲取一段時間沒有獲取到,獲取超時,設置超市標誌爲true
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
/**
* 該方法的作用就是去執行任務
*/
final void runWorker(Worker w) {
//獲取當前線程
Thread wt = Thread.currentThread();
//獲取worker裏的任務
Runnable task = w.firstTask;
//將worker實例的任務賦值爲null
w.firstTask = null;
/*
*unlock方法會調用AQS的release方法
*release方法會調用具體實現類也就是Worker的tryRelease方法
*也就是將AQS狀態置爲0,允許中斷
*/
w.unlock(); // allow interrupts
//是否突然完成
boolean completedAbruptly = true;
try {
//worker實例的task不爲空,或者通過getTask獲取的不爲空
while (task != null || (task = getTask()) != null) {
//獲取鎖
w.lock();
/*獲取線程池的控制狀態,至少要大於STOP狀態
*如果狀態不對,檢查當前線程是否中斷並清除中斷狀態,並且再次檢查線程池狀態是否大於STOP
*如果上述滿足,檢查該對象是否處於中斷狀態,不清除中斷標記
*/
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
task = null;
//已完成任務數+1
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
//處理並退出當前worker
processWorkerExit(w, completedAbruptly);
}
}
// Public constructors and methods
/**
* 參數 類型 含義
corePoolSize int 核心線程數
maximumPoolSize int 最大線程數
keepAliveTime long 存活時間
unit TimeUnit 時間單位
workQueue BlockingQueue 存放線程的隊列
threadFactory ThreadFactory 創建線程的工廠
handler RejectedExecutionHandler 多餘的的線程處理器(拒絕策略)
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
/**
*在將來的某個時候執行給定的任務。該任務可以在新線程或現有池線程中執行。如果由於該執行器已關閉或已達到其 容量而無法提交以供執行,則該任務將由當前拒絕策略處理
* the task is handled by the current {@code RejectedExecutionHandler}.
*
*
*/
public void execute(Runnable command) {
//需要執行的任務command爲空,拋出空指針異常
if (command == null)
throw new NullPointerException();
/*
*執行的流程實際上分爲三步
*1、如果運行的線程小於corePoolSize,以用戶給定的Runable對象新開一個線程去執行
* 並且執行addWorker方法會以原子性操作去檢查runState和workerCount,以防止當返回false的
* 時候添加了不應該添加的線程
*2、 如果任務能夠成功添加到隊列當中,我們仍需要對添加的線程進行雙重檢查,有可能添加的線程在前
* 一次檢查時已經死亡,又或者在進入該方法的時候線程池關閉了。所以我們需要複查狀態,並有有必
* 要的話需要在停止時回滾入列操作,或者在沒有線程的時候新開一個線程
*3、如果任務無法入列,那我們需要嘗試新增一個線程,如果新建線程失敗了,我們就知道線程可能關閉了
* 或者飽和了,就需要拒絕這個任務
*
*/
//獲取線程池的狀態
int c = ctl.get();
//通過workCountOf方法算workerCount值,小於corePoolSize
if (workerCountOf(c) < corePoolSize) {
//處於運行狀態的線程數小於核心線程數,添加任務到worker集合當中
//添加核心任務
if (addWorker(command, true))
//成功返回
return;
//失敗的話再次獲取線程池的狀態
c = ctl.get();
}
/*
* 運行狀態的線程數 不小於核心數時,堵塞隊列沒滿
* 線程池還在運行,將新的線程插入阻塞隊列中
判斷線程池是否正處於RUNNING狀態
*是的話添加Runnable對象到workQueue隊列當中
*/
if (isRunning(c) && workQueue.offer(command)) {
//再次獲取線程池的狀態
int recheck = ctl.get();
//再次檢查狀態
//線程池不處於RUNNING狀態,將任務從workQueue隊列中移除
if (! isRunning(recheck) && remove(command))
//拒絕任務
reject(command);
//如果此時線程池的工作線程個數爲0,加入新的非核心任務
else if (workerCountOf(recheck) == 0)
//添加非核心的worker 爲null
addWorker(null, false);
}
//隊列滿的話,就添加到非核心任務
else if (!addWorker(command, false))
//執行失敗則拒絕任務
reject(command);
}
/**
* 當調用shutdown方法時,線程池將不會再接收新的任務,然後將先前放在隊列中的任務執行完成。
shutdown和shutdownNow這兩個方法的作用都是關閉線程池,流程大致相同,只有幾個步驟不同
加鎖
檢查關閉權限
CAS改變線程池狀態
設置中斷標誌(線程池不在接收任務,隊列任務會完成)/中斷當前執行的線程
調用onShutdown方法(給子類提供的方法)/獲取隊列中的任務
解鎖
嘗試將線程池狀態變成終止狀態TERMINATED
結束/返回隊列中的任務
*
* @throws SecurityException {@inheritDoc}
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
/**
* 立即停止所有的執行任務,並將隊列中的任務返回
*
* @throws SecurityException {@inheritDoc}
*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
public boolean isShutdown() {
return ! isRunning(ctl.get());
}
/**
* 表示如果此執行程序處於在 shutdown 或 shutdownNow 之後正在終止但尚未完全終止的過程中,則返回 true。
*
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
//表示如果關閉後所有任務都已完成,則返回 true
public boolean isTerminated() {
return runStateAtLeast(ctl.get(), TERMINATED);
}
/**接收人timeout和TimeUnit兩個參數,用於設定超時時間及單位。當等待超過設定時間時,會監測 *ExecutorService是否已經關閉,若關閉則返回true,否則返回false。一般情況下會和shutdown方法組合使用。
*/
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
//如果已經關閉 返回null
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)
//如果等待時間<=0 返回false
return false;
//Condition的awaitNanos的實現過程
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
/**
* 當這個執行器不再被引用並且沒有線程時,調用shutdown。
*/
protected void finalize() {
SecurityManager sm = System.getSecurityManager();
//sm? acc?
if (sm == null || acc == null) {
shutdown();
} else {
PrivilegedAction<Void> pa = () -> { shutdown(); return null; };
AccessController.doPrivileged(pa, acc);
}
}
/**
*
* 設置線程工廠去生成新的線程。
* @throws NullPointerException if threadFactory is null
* @see #getThreadFactory
*/
public void setThreadFactory(ThreadFactory threadFactory) {
if (threadFactory == null)
throw new NullPointerException();
this.threadFactory = threadFactory;
}
/**
* 得到線程工廠
*/
public ThreadFactory getThreadFactory() {
return threadFactory;
}
/**
*
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
if (handler == null)
throw new NullPointerException();
this.handler = handler;
}
/**
*
*/
public RejectedExecutionHandler getRejectedExecutionHandler() {
return handler;
}
/**
* 設置線程的核心數。這將重寫構造函數中設置的任何值。如果新值小於當前值,則多餘的現有線程將在下次變爲空閒 時終止。如果更大,如果需要,將啓動新線程來執行任何排隊的任務。
*
* @param corePoolSize 新線程的核心數。
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @see #getCorePoolSize
*/
public void setCorePoolSize(int corePoolSize) {
//如果核心線程數 <0 拋異常
if (corePoolSize < 0)
throw new IllegalArgumentException();
//新core數 - 對象的core數
int delta = corePoolSize - this.corePoolSize;
//設置對象的core數 爲新的core數
this.corePoolSize = corePoolSize;
//工作線程數 大於新的核心線程數 中斷workers集合中的空閒任務
if (workerCountOf(ctl.get()) > corePoolSize)
interruptIdleWorkers();
//如果比之前的線程數大
else if (delta > 0) {
// We don't really know how many new threads are "needed".
// As a heuristic, prestart enough new workers (up to new
// core size) to handle the current number of tasks in
// queue, but stop if queue becomes empty while doing so.
//如果新值比原值大,且隊列中還存在任務,則馬上新增worker來處理
int k = Math.min(delta, workQueue.size());
while (k-- > 0 && addWorker(null, true)) {
if (workQueue.isEmpty())
break;
}
}
}
/**
* Returns the core number of threads.
*
* @return the core number of threads
* @see #setCorePoolSize
*/
public int getCorePoolSize() {
return corePoolSize;
}
/**
* 工作線程數 小於核心線程數 ,預先創建好corePoolSize一個線程。
*
* @return {@code true} if a thread was started
*/
public boolean prestartCoreThread() {
return workerCountOf(ctl.get()) < corePoolSize &&
addWorker(null, true);
}
/**
* 與prestartCoreThread相同,不同之處在於即使corePoolSize爲0,也會安排至少啓動一個線程。
*/
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}
/**
* 啓動所有核心線程,導致它們空閒地等待工作。這將覆蓋僅在執行新任務時啓動核心線程的默認策略。
*
* @return the number of threads started
*/
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))
++n;
return n;
}
/**
* 如果此池允許核心線程超時,則返回true;如果在keepAlive時間內沒有任務到達,則返回terminate;如果需要,則在新任務到達時替換。如果爲true,則應用於非核心線程的相同保持活動策略也適用於核心線程。如果爲false(默認值),則不會由於缺少傳入任務而終止核心線程。
*
* @return {@code true} if core threads are allowed to time out,
* else {@code false}
*
* @since 1.6
*/
public boolean allowsCoreThreadTimeOut() {
return allowCoreThreadTimeOut;
}
/**
*設置是否允許超時
*
* @param value {@code true} if should time out, else {@code false}
* @throws IllegalArgumentException if value is {@code true}
* and the current keep-alive time is not greater than zero
*
* @since 1.6
*/
public void allowCoreThreadTimeOut(boolean value) {
//如果允許超時,超時時間必須大於0
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
//如果新值和舊值不同 重新賦值,且如果允許,中斷workers集合中的空閒任務
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;
if (value)
interruptIdleWorkers();
}
}
/**
* 設置允許的最大線程數。這將重寫構造函數中設置的任何值。如果新值小於當前值,則多餘的現有線程將在下次變爲空閒時終止。
*
* @param maximumPoolSize the new maximum
* @throws IllegalArgumentException if the new maximum is
* less than or equal to zero, or
* less than the {@linkplain #getCorePoolSize core pool size}
* @see #getMaximumPoolSize
*/
public void setMaximumPoolSize(int maximumPoolSize) {
//最大線程池數量 必須大於0且不小於核心線程數
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
throw new IllegalArgumentException();
this.maximumPoolSize = maximumPoolSize;
//如果新值小於當前值,則多餘的現有線程將在下次變爲空閒時終止。
if (workerCountOf(ctl.get()) > maximumPoolSize)
interruptIdleWorkers();
}
/**
*
*/
public int getMaximumPoolSize() {
return maximumPoolSize;
}
/**
* 設置線程在終止之前可以保持空閒的時間限制。如果池中當前的線程數超過核心數,則在等待此時間而不處理任務後,將終止多餘的線程。這將重寫構造函數中設置的任何值。
*
* @param time the time to wait. A time value of zero will cause
* excess threads to terminate immediately after executing tasks.
* @param unit the time unit of the {@code time} argument
* @throws IllegalArgumentException if {@code time} less than zero or
* if {@code time} is zero and {@code allowsCoreThreadTimeOut}
* @see #getKeepAliveTime(TimeUnit)
*/
public void setKeepAliveTime(long time, TimeUnit unit) {
//如果空閒時間限制 小於0 報錯
if (time < 0)
throw new IllegalArgumentException();
//如果空閒時間限制等於0且允許超時 報錯
if (time == 0 && allowsCoreThreadTimeOut())
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
//如果新值小於舊值,多餘的現有線程將在下次變爲空閒時終止。
long keepAliveTime = unit.toNanos(time);
long delta = keepAliveTime - this.keepAliveTime;
this.keepAliveTime = keepAliveTime;
if (delta < 0)
interruptIdleWorkers();
}
/**
* Returns the thread keep-alive time, which is the amount of time
* that threads in excess of the core pool size may remain
* idle before being terminated.
*
* @param unit the desired time unit of the result
* @return the time limit
* @see #setKeepAliveTime(long, TimeUnit)
*/
public long getKeepAliveTime(TimeUnit unit) {
return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
}
/* User-level queue utilities */
/**
* Returns the task queue used by this executor. Access to the
* task queue is intended primarily for debugging and monitoring.
* This queue may be in active use. Retrieving the task queue
* does not prevent queued tasks from executing.
*
* @return the task queue
*/
public BlockingQueue<Runnable> getQueue() {
return workQueue;
}
/**
* 移除一個任務
*/
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
//以防 關閉或者爲空,嘗試中斷。
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
/**
* 嘗試從工作隊列中刪除所有已取消的{@link Future}任務。此方法可以用作對功能沒有其他影響的存儲回收操作。取消的任務永遠不會執行,但可能會累積在工作隊列中,直到工作線程可以主動刪除它們。相反,調用此方法會嘗試立即刪除它們。但是,在其他線程的干擾下,此方法可能無法刪除任務。
*/
public void purge() {
final BlockingQueue<Runnable> q = workQueue;
try {
Iterator<Runnable> it = q.iterator();
while (it.hasNext()) {
Runnable r = it.next();
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
it.remove();
}
} catch (ConcurrentModificationException fallThrough) {
// Take slow path if we encounter interference during traversal.
// Make copy for traversal and call remove for cancelled entries.
// The slow path is more likely to be O(N*N).
for (Object r : q.toArray())
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
q.remove(r);
}
tryTerminate(); // In case SHUTDOWN and now empty
}
/* Statistics */
/**
* 返回池中當前線程數。
*
* @return the number of threads
*/
public int getPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
刪除isTerminated()&&getPoolSize()>0的罕見且令人驚訝的可能性
return runStateAtLeast(ctl.get(), TIDYING) ? 0
: workers.size();
} finally {
mainLock.unlock();
}
}
/**
* 返回正在積極執行任務的線程的大致數目。
*
* @return the number of threads
*/
public int getActiveCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int n = 0;
for (Worker w : workers)
if (w.isLocked())
++n;
return n;
} finally {
mainLock.unlock();
}
}
/**
* 返回池中同時存在的最大線程數。
*
* @return the number of threads
*/
public int getLargestPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
return largestPoolSize;
} finally {
mainLock.unlock();
}
}
/**
* 返回已計劃執行的任務的大致總數。由於任務和線程的狀態在計算期間可能會動態更改,因此返回的值只是一個近似值。
*
* @return the number of tasks
*/
public long getTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers) {
n += w.completedTasks;
if (w.isLocked())
++n;
}
return n + workQueue.size();
} finally {
mainLock.unlock();
}
}
/**
* 返回已完成執行的任務的大致總數。由於任務和線程的狀態在計算過程中可能會動態變化,因此返回的值只是一個近似值,但在連續的調用中不會減少。
*
* @return the number of tasks
*/
public long getCompletedTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers)
n += w.completedTasks;
return n;
} finally {
mainLock.unlock();
}
}
/**
* 返回標識此池及其狀態的字符串,包括運行狀態的指示以及估計的工作進程和任務計數。
* 注意一個類的toString方法都要加鎖。- -
* @return a string identifying this pool, as well as its state
*/
public String toString() {
long ncompleted;
int nworkers, nactive;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
ncompleted = completedTaskCount;
nactive = 0;
nworkers = workers.size();
for (Worker w : workers) {
ncompleted += w.completedTasks;
if (w.isLocked())
++nactive;
}
} finally {
mainLock.unlock();
}
int c = ctl.get();
String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
(runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down"));
return super.toString() +
"[" + rs +
", pool size = " + nworkers +
", active threads = " + nactive +
", queued tasks = " + workQueue.size() +
", completed tasks = " + ncompleted +
"]";
}
/* Extension hooks */
/**
* 執行前的方法,由子類具體實現
*
* @param t the thread that will run task {@code r}
* @param r the task that will be executed
*/
protected void beforeExecute(Thread t, Runnable r) { }
/**
* Method invoked upon completion of execution of the given Runnable.
* This method is invoked by the thread that executed the task. If
* non-null, the Throwable is the uncaught {@code RuntimeException}
* or {@code Error} that caused execution to terminate abruptly.
*
* <p>This implementation does nothing, but may be customized in
* subclasses. Note: To properly nest multiple overridings, subclasses
* should generally invoke {@code super.afterExecute} at the
* beginning of this method.
*
* <p><b>Note:</b> When actions are enclosed in tasks (such as
* {@link FutureTask}) either explicitly or via methods such as
* {@code submit}, these task objects catch and maintain
* computational exceptions, and so they do not cause abrupt
* termination, and the internal exceptions are <em>not</em>
* passed to this method. If you would like to trap both kinds of
* failures in this method, you can further probe for such cases,
* as in this sample subclass that prints either the direct cause
* or the underlying exception if a task has been aborted:
*
* <pre> {@code
* class ExtendedExecutor extends ThreadPoolExecutor {
* // ...
* protected void afterExecute(Runnable r, Throwable t) {
* super.afterExecute(r, t);
* if (t == null && r instanceof Future<?>) {
* try {
* Object result = ((Future<?>) r).get();
* } catch (CancellationException ce) {
* t = ce;
* } catch (ExecutionException ee) {
* t = ee.getCause();
* } catch (InterruptedException ie) {
* Thread.currentThread().interrupt(); // ignore/reset
* }
* }
* if (t != null)
* System.out.println(t);
* }
* }}</pre>
*
* @param r the runnable that has completed
* @param t the exception that caused termination, or null if
* execution completed normally
*/
protected void afterExecute(Runnable r, Throwable t) { }
/**
* Method invoked when the Executor has terminated. Default
* implementation does nothing. Note: To properly nest multiple
* overridings, subclasses should generally invoke
* {@code super.terminated} within this method.
*/
protected void terminated() { }
/* Predefined RejectedExecutionHandlers */
/**
* 一種被拒絕任務的處理程序,它直接在{@code execute}方法的調用線程中運行被拒絕的任務,除非執行程序已關閉,在這種情況下,該任務將被丟棄。.
只用調用者所在線程來運行任務。
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
/**
* 直接拋異常RejectedExecutionException的策略
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
/**
*一個被拒絕任務的處理程序,它會自動放棄被拒絕的任務。
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
/**
* 被拒絕任務的處理程序,該處理程序丟棄最舊的未處理請求,然後重試{@code execute},除非該執行程序關閉,否則該任務將被丟棄。
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
//最舊的執行
e.getQueue().poll();
e.execute(r);
}
}
}
}
六. 總結
1. 線程池執行步驟
execute方法
- 工作線程數 < corePoolSize 新增工作線程addWorker()方法
- 工作線程 >= corePoolSize ,將任務放入阻塞隊列中,直到阻塞隊列滿了
- 阻塞隊列滿了,新增非核心線程數 工作線程必須<=maxPoolSize addWorker()方法,如果超過最大線程數 拒絕
addWorker方法
創建工作線程,並且調用工作線程的runWorker()方法,循環調用工作線程的firstTask或者從阻塞隊列中take任務。每次調用完成後刪除這個任務。