ThreadPoolExecutor 代碼解析
本文源碼解析基於JDK1.8
本人愚見,若有錯誤,請指正,謝謝
ThreadPoolExecutor是Java中的線程池的核心類。用Executors創建的線程池本質也是用的該類,定時任務用到的ScheduleThreadPoolExecutor是繼承於此類。
Executor的初始化
ThreadPoolExecutor的變量和常量
ThreadPoolExecutor定義了一個原子類對象ctl,用來保存線程池的狀態和線程池的線程數量。Integer數據類型長度有32位,ctl將高位3位保存狀態標誌,低位29位保存worker數量。初始化後,默認狀態是RUNNING,線程數量是0。
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 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;
COUNT_BITS是worker數量所佔用的位數,此處爲29。
CAPACITY 是worker的最大數量,
線程池共有5個狀態:狀態由ctl的高三位保存。
狀態 | 狀態位 | 描述 |
---|---|---|
RUNNING | 111 | 線程池初始化後的默認狀態,接收並處理任務 |
SHUTDOWN | 000 | 調用shutdown()方法後的狀態,拒絕接收任務,但會處理隊列中的任務 |
STOP | 001 | 調用shutdownNow()方法後的狀態,拒絕接收任務,同時中斷正在運行的任務 |
TIDYING | 010 | 工作隊列爲空,同時線程數量爲0時的狀態,有個terminated()的hook |
TERMINATED | 011 | 線程池停止 |
ThreadPoolExecutor的構造器
ThreadPoolExecutor共有4個構造器,最根本的是參數最多的那個。此構造器參數有7位,分別是:
參數名 | 描述 |
---|---|
corePoolSize | 核心線程池大小,核心線程是指在空閒情況下依然能存活的線程,除非allowCoreThreadTimeOut()設置爲true |
maximumPoolSize | 線程池持有的最大線程數量 |
keepAliveTime | 線程存活時間,當線程數量大於corePoolSize時,空閒線程在關閉前等待task的最大時間 |
unit | 線程存活時間單位,keepAliveTime的單位 |
workQueue | 用來暫時保存任務的隊列 |
threadFactory | 線程工廠,executor創建thread的工廠 |
handler | 當ThreadPoolExecutor關閉或ThreadPoolExecutor已經飽和時,execute()調用的飽和策略 |
源碼如下:
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;
}
類中還有個變量allowCoreThreadTimeOut,用來設置coreThread是否可以在空閒時超時關閉,需要用allowCoreThreadTimeOut方法來設置。
public void allowCoreThreadTimeOut(boolean value) {
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;
if (value)
interruptIdleWorkers();
}
}
調用execute()方法提交任務
ThreadPoolExecutor可以使用submit()或者execute()方法提交任務,區別在於submit()可以提交Callable的任務,就是帶有返回值的任務,但是callable對象會被包裝成runnable對象,還是調用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);
}
一個task提交後,線程池的處理流程如下:
1. 核心線程池還未滿,則創建一個新的核心線程執行任務。新建核心線程成功,方法結束返回。如果失敗,則獲取新的ctl值,進入步驟2。
2. 判斷線程池是在運行且成功添加任務到工作隊列中,則獲取新的ctl,再次判斷狀態。如果狀態爲非運行,且成功從工作隊列中移出任務,則拒絕任務。如果是運行狀態或者移除任務失敗,移出任務失敗說明此任務可能被執行或者遇到shutdownNow()方法,任務被移除隊列,運行狀態的話,這裏判斷線程數量爲0(不理解),添加一個非核心線程。
3. 如果任務無法加到工作隊列中,或者線程池不在運行狀態:如果是線程池關閉,則不考慮後續;如果是工作隊列已滿,則添加非核心線程處理任務。如果線程池已滿,無法添加非核心線程,則拒絕任務。
工作線程Worker
工作線程Worker類
工作線程Worker是ThreadPoolExecutor的內部類,繼承了AbstractQueuedSynchronizer,封裝了線程和任務,並且維護了一個state狀態。state在初始化時是-1,防止在工作線程還未運行時,就被interrupts。在開始運行時,設置爲0。並且在執行任務開始前後分別設置爲1,0,等待task時的state是0,目的是將正在運行task和等待task的worker區別開,以便在修改線程池參數或者shutdown時可以interrupt等待任務的worker。
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
final Thread thread;
volatile long completedTasks;
Worker(Runnable firstTask) {
setState(-1); // 設置state爲-1,防止線程還未start,就被interrupt
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
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;
// 由shutdownNow()調用
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
worker的創建
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()))
// 上述的rs >= SHUTDOWN && !(rs==shutdown && firstTask==null && !workQueue.isEmpty())可以推導爲
// rs >= SHUTDOWN && (rs!=shutdown || firstTask!=null || workQueue.isEmpty())
// 也就是:
// 線程池在running狀態,添加工作線程
// 線程池在shutdown狀態下,firstTask不爲空,不添加工作線程,此處返回false,應該是要reject。
// 線程池在shutdown狀態下,firstTask爲空,workQueue爲空時,不添加工作線程,換句話說workQueue不爲空時,可以添加線程加快處理速度。
// 線程池在stop,tidying,terminated狀態下,不添加工作線程
return false;
for (;;) {
int wc = workerCountOf(c);
// 當前線程池的工作線程數量達到最大數量,或者核心線程數量或最大線程數量達到上限,返回false。
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
// 原子類的CAS操作
// 工作線程數+1,如果狀態改變或者工作線程數變化,則CAS更新失敗
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 如果狀態不變,就自循環增加wc,如果狀態變了,就需要重新判斷狀態。
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 {
// 初始化新的worker,用threadFactory創建新的線程
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive())
throw new IllegalThreadStateException();
workers.add(w);
// 更新同一時間最多用到多少個線程largestPoolSize
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;
}
worker的運行
其中的run()方法調用runWorker()方法就是執行task的方法了。
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();
// 如果線程池在STOP及之後狀態,而且線程不是中斷的,則中斷線程
// 因爲有可能調用shutdownNow(),所以這裏有第二次檢查,也是檢查線程池狀態,Thread.interrupted()是用來判斷線程是否中斷,同時清除中斷標誌。
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task); // hook
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); // hook
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
// 如果task爲null,或者task順利執行完,設置爲false;如果task報錯,爲true
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
worker的晚年
worker有幾種結束的情況:
1. 線程池調用shutdownNow(),中斷線程退出。這種情況就不會新建線程。
2. 任務報錯退出,如果線程池在RUNNING和shutdown狀態,會新建一個線程繼續處理任務。
3. 正常運行結束,因爲while循環會一直拿task,所以正常結束意味着沒任務或者STOP狀態不給任務。如果當前線程數能滿足要求(核心線程數或者1個線程),則不創建新線程。
worker結束後,從workers裏移除,並嘗試關閉線程池。
//worker最後的時光
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount();
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
completedTaskCount += w.completedTasks;
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate();
int c = ctl.get();
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && ! workQueue.isEmpty())
min = 1;
if (workerCountOf(c) >= min)
return; // replacement not needed
}
addWorker(null, false);
}
}
worker獲取食物
getTask()用於獲取任務
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
if ((wc > maximumPoolSize || (timed && timedOut))
&& (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
getTask()是獲取任務的方法,線程空閒時間超時也是這裏控制的。有幾種情況是拿不到task的:
1. 線程池是stop狀態
2. 線程池是shutdown狀態,並且工作隊列爲null。
3. 線程數大於maximumPoolSize,在變更maximumPoolSize參數後,有可能發生。
4. 線程數大於corePoolSize,並且超時
5. 在allowCoreThreadTimeOut 爲true時,線程數大於1,並且獲取task超時。
6. 在allowCoreThreadTimeOut 爲true時,工作隊列沒有task,並且獲取task超時。
在拿不到task的情況,會將線程數-1,並且return null。
線程池的終結
馬上終結
shutdownNow()用來立刻結束線程池,中斷所有線程,並且返回還未執行的任務。
終結的步驟:
1. 檢查shutdown的權限,調用其他thread的interrupt方法需要權限。
2. 設置線程池狀態爲stop,如果線程池狀態已經是STOP,TIDYING,TERMINATED,則不更改。
3. 中斷所有工作線程。
4. 取出尚未執行的任務作爲返回值。
5. 調用tryTerminate結束線程池。
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;
}
慢慢終結
shutdown()方法用來有計劃地結束線程池:
1. 首先拒絕接收新任務。
2. 然後檢查shutdown權限
3. 設置線程池狀態爲shutdown
4. 中斷所有空閒線程
5. 執行完所有任務後,才真正結束線程池。
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
真正關閉線程池的主角
tryTerminate()這個方法會真正將線程池設置爲terminated狀態。
步驟:
1. RUNNING,TIDYING,TERMINATED狀態直接返回,shutdown狀態下還有任務的情況下,返回
2. 工作線程數量不爲0時,中斷空閒線程,返回
3. 1和2都不滿足的情況下,設置線程池狀態爲TIDYING
4. 調用terminated()方法,這是個hook,爲TIDYING準備的
5. 設置狀態爲TERMINATED,
final void tryTerminate() {
for (;;) {
int c = ctl.get();
if (isRunning(c) ||
runStateAtLeast(c, TIDYING) ||
(runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
return;
if (workerCountOf(c) != 0) { // Eligible to terminate
interruptIdleWorkers(ONLY_ONE);
return;
}
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0));
termination.signalAll();
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
在調用shutdown, shutdownNow後,並不是方法結束,線程池就結束的,所以tryTerminate方法在其他方法中也有調用:
1. addWorkerFailed(),這個方法是在增加工作線程失敗時調用
2. processWorkerExit(),工作線程結束時調用
3. shutdown()
4. shutdownNow()
5. remove(),這個方法用來刪除任務
6. purge(),這個方法用來移除工作隊列中的Callable任務
等待終結
Executor提供了一個方法awaitTermination,用來判斷在指定時間內,線程池有沒有關閉。
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos);
}
} finally {
mainLock.unlock();
}
}
finalize()
在線程池不被引用,而且沒有線程時,GC會清理掉這個對象,在清理之前會調用這個方法。
protected void finalize() {
shutdown();
}