Java提供了幾種便捷的方法創(chuàng)建線程池,通過(guò)這些內(nèi)置的api就能夠很輕松的創(chuàng)建線程池。在java.util.concurrent包中的Executors類,其中的靜態(tài)方法就是用來(lái)創(chuàng)建線程池的:
- newFixedThreadPool():創(chuàng)建一個(gè)固定線程數(shù)量的線程池,而且線程池中的任務(wù)全部執(zhí)行完成后,空閑的線程也不會(huì)被關(guān)閉。
- newSingleThreadExecutor():創(chuàng)建一個(gè)只有一個(gè)線程的線程池,空閑時(shí)也不會(huì)被關(guān)閉。
- newCachedThreadPool():創(chuàng)建一個(gè)可緩存的線程池,線程的數(shù)量為
Integer.MAX_VALUE,空閑線程會(huì)臨時(shí)緩存下來(lái),線程會(huì)等待60s還是沒(méi)有任務(wù)加入的話就會(huì)被關(guān)閉。
Executors類中還有一些創(chuàng)建線程池的方法(jdk8新加的),但是現(xiàn)在這個(gè)觸極到我的知識(shí)盲區(qū)了~~

上面那幾個(gè)方法,其實(shí)都是創(chuàng)建了一個(gè)ThreadPoolExecutor對(duì)象作為返回值,要搞清楚線程池的原理主要還是要分析ThreadPoolExecutor這個(gè)類。
ThreadPoolExecutor的構(gòu)造方法:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
...
}
ThreadPoolExecutor的構(gòu)造方法包含以下幾個(gè)參數(shù):
- corePoolSize: 核心線程數(shù)量,常駐線程池中的線程,即時(shí)線程池中沒(méi)有任務(wù)可執(zhí)行,也不會(huì)被關(guān)閉。
- maximumPoolSize:最大線程數(shù)量
- keepAliveTime:空閑線程存活時(shí)間
- unit: 空閑線程存活時(shí)間的單位
- workQueue:工作隊(duì)列,線程池一下忙不過(guò)來(lái),那新來(lái)的任務(wù)就需要排隊(duì),排除中的任務(wù)就會(huì)放在workQueue中
- threadFactory:線程工廠,創(chuàng)建線程用的
- handler:
RejectedExecutionHandler實(shí)例用于在線程池中沒(méi)有空閑線程能夠執(zhí)行任務(wù),并且workQueue中也容不下任務(wù)時(shí)拒絕任務(wù)時(shí)的策略。
ThreadPoolExecutor中的線程統(tǒng)稱為工作線程,但有一個(gè)小概念是核心線程,核心線程由參數(shù)corePoolSize指定,如corePoolSize設(shè)置5,那線程池中就會(huì)有5條線程常駐線程池中,不會(huì)被回收掉,但是也會(huì)有例外,如果allowCoreThreadTimeOut為true空閑一段時(shí)間后,也會(huì)被關(guān)閉。
線程的狀態(tài)和工作線程數(shù)量
線程中的狀態(tài)和工作線程和數(shù)量都是由ctl表示,是一個(gè)AtomicInteger類型的屬性:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
ctl的高四位為線程的狀態(tài),其他位數(shù)為工作線程的數(shù)量,所以線程中最大的工作線程數(shù)量為(2^29)-1。
線程池中的狀態(tài)有五種:
- RUNNING:接收新的任務(wù)和處理隊(duì)列中的任務(wù)
- SHUTDOWN:不能新增任務(wù),但是會(huì)繼續(xù)處理已經(jīng)添加的任務(wù)
- STOP:不能新增任務(wù),不會(huì)繼續(xù)處理已經(jīng)添加任務(wù)
- TIDYING:所有的任務(wù)已經(jīng)被終止,工作線程為0
- TERMINATED:terminated()方法執(zhí)行完成
狀態(tài)碼的定義如下:
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;
創(chuàng)建線程池
如果有面試官問(wèn):如何正確的創(chuàng)建線程池?千萬(wàn)不要說(shuō)使用Executors創(chuàng)建線程,雖然Executors能很方便的創(chuàng)建線程池,但是他提供的靜態(tài)創(chuàng)建方法會(huì)有一些坑。
主要的原因是:maximumPoolSize和workQueue這兩個(gè)參數(shù)
Executors靜態(tài)方法在創(chuàng)建線程池時(shí),如果maximumPoolSize設(shè)置為Integer.MAX_VALUE,這樣會(huì)導(dǎo)致線程池可以一直要以接收運(yùn)行任務(wù),可能導(dǎo)致cpu負(fù)載過(guò)高。
workQueue是一個(gè)阻塞隊(duì)列的實(shí)例,用于放置正在等待執(zhí)行的任務(wù)。如果在創(chuàng)建線程種時(shí)workQueue實(shí)例沒(méi)有指定任務(wù)的容量,那么等待隊(duì)列中可以一直添加任務(wù),極有可能導(dǎo)致oom。
所以創(chuàng)建線程,最好是根據(jù)線程池的用途,然后自己創(chuàng)建線程。
添加任務(wù)
調(diào)用線程池的execute并不是立即執(zhí)行任務(wù),線程池內(nèi)部用經(jīng)過(guò)一頓操作,如:判斷核心線程數(shù)、是否需要添加到等待隊(duì)列中。
下來(lái)的代碼是execute的源碼,代碼很簡(jiǎn)潔只有2個(gè)if語(yǔ)句:
public void execute(Runnable command) {
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);
}
- 第一個(gè)if,如果當(dāng)前線程池中的工作線程數(shù)量小于
corePoolSize,直接創(chuàng)建一個(gè)工作線程執(zhí)行任務(wù) - 第二個(gè)if,當(dāng)線程池處于運(yùn)行狀態(tài),調(diào)用
workQueue.offer(command)方法將任務(wù)添加到workQueue,否則調(diào)用addWorker(command, false)嘗試去添加一個(gè)工作線程。
整理了一張圖,把線程池分為三部分Core Worker、Worker、workQueue:

換一種說(shuō)法,在調(diào)用execute方法時(shí),任務(wù)首先會(huì)放在Core Worker內(nèi),然后才是workQueue,最后才會(huì)考慮Worker。
這樣做的原因可以保證Core Worker中的任務(wù)執(zhí)行完成后,能立即從workQueue獲取下一個(gè)任務(wù),而不需要啟動(dòng)別的工作線程,用最少的工作線程辦更多的事。
創(chuàng)建工作線程
在execute方法中,有三個(gè)地方調(diào)用了addWorker。addWorker方法可以分為二部分:
- 增加工作線程數(shù)量
- 啟動(dòng)工作線程
addWorker的方法簽名如下:
private boolean addWorker(Runnable firstTask, boolean core)
-
firstTask:第一個(gè)運(yùn)行的任務(wù),可以為空。如果為空任務(wù)會(huì)從
workQueue中獲取。 - core: 是否是核心工作線程
增加工作線程數(shù)量
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
....
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
}
}
上面代碼省略了一部分代碼,主要代碼都在for循環(huán)中,利用CAS鎖,安全的完成線程池狀態(tài)的檢查與增加工作線程的數(shù)量。其中的compareAndIncrementWorkerCount(c)調(diào)用就是將工作線程數(shù)量+1。
啟動(dòng)工作線程
增加工作線程的數(shù)量后,緊接著就會(huì)啟動(dòng)工作線程:
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);
}
啟動(dòng)工作線程的流程:
- 創(chuàng)建一個(gè)
Worker實(shí)例,Worker構(gòu)造方法會(huì)使用ThreadFactory創(chuàng)建一個(gè)線程
w = new Worker(firstTask);
final Thread t = w.thread;
就不說(shuō)Worker類的實(shí)現(xiàn)了,直接給出構(gòu)造方法來(lái)細(xì)品:
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
- 如果線程池狀態(tài)是在運(yùn)行中,或者已經(jīng)關(guān)閉,但工作線程要從
workQueue中獲取任務(wù),才能添加工作線程
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;
}
注意::當(dāng)線程池處于SHUTDOWN狀態(tài)時(shí),它不能接收新的任務(wù),但是可以繼續(xù)執(zhí)行未完成的任務(wù)。任務(wù)是否從workQueue中獲取,是根據(jù)firstTask判斷,每個(gè)Worker實(shí)例都有一個(gè)firstTask屬性,如果這個(gè)值為null,工作線程啟動(dòng)的時(shí)候就會(huì)從workQueue中獲取任務(wù),否則會(huì)執(zhí)行firstTask。
- 啟動(dòng)線程
調(diào)用線程的start方法,啟動(dòng)線程。
if (workerAdded) {
t.start();
workerStarted = true;
}
執(zhí)行任務(wù)
回過(guò)頭來(lái)看一個(gè)Worker類的定義:
private final class Worker extends AbstractQueuedSynchronizer
implements Runnable{
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
...
}
Worker類實(shí)現(xiàn)了Runnable接口,同時(shí)在構(gòu)造方法中會(huì)將this傳遞給線程,到這里你就知道了Worker實(shí)例中有run方法,它會(huì)在線程啟動(dòng)后執(zhí)行:
public void run() {
runWorker(this);
}
run方法內(nèi)部接著調(diào)用runWorker方法運(yùn)行任務(wù),在這里才是真正的開始運(yùn)行任務(wù)了:
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 pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
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);
}
}
- 獲取任務(wù)
首先將firstTask傳遞給task臨時(shí)變量:
Runnable task = w.firstTask;
然后循環(huán)檢查task或者從workQueue中獲取任務(wù):
while (task != null || (task = getTask()) != null) {
...
}
getTask()稍后再做分析。
- 運(yùn)行任務(wù)
去掉一些狀態(tài)檢查、異常捕獲、和勾子方法調(diào)用后,保留最重要的調(diào)用task.run():
while (task != null || (task = getTask()) != null) {
...
task.run();
...
}
task其實(shí)就是通過(guò)調(diào)用execute方法傳遞進(jìn)來(lái)的Runnable實(shí)例,也就是你的任務(wù)。只不過(guò)它可能保存在Worker.firstTask中,或者在workQueue中,保存在哪里在前面的任務(wù)添加順序中已經(jīng)說(shuō)明。
從workQueue中獲取任務(wù)
試想一下如果每個(gè)任務(wù)執(zhí)行完成,就關(guān)閉掉一個(gè)線程那有多浪費(fèi)資源,這樣使用線程池也沒(méi)有多大的意義。所以線程的主要的功能就是線程復(fù)用,一旦任務(wù)執(zhí)行完成直接去獲取下一個(gè)任務(wù),或者掛起線程等待下一個(gè)提交的任務(wù),然后等待一段時(shí)間后還是沒(méi)有任務(wù)提交,然后才考慮是否關(guān)閉部分空閑的線程。
runWorker中會(huì)循環(huán)的獲取任務(wù):
while (task != null || (task = getTask()) != null) {
...
task.run();
...
}
上面的代碼getTask()就是從workQueue中獲取任務(wù):
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
...
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
...
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
獲取任務(wù)的時(shí)候會(huì)有兩種方式:
- 超時(shí)等待獲取任務(wù)
- 一直等待任務(wù),直到有新任務(wù)
如果allowCoreThreadTimeOut為true,corePoolSize指定的核心線程數(shù)量會(huì)被忽略,直接使用 workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) 獲取任務(wù),否則的話會(huì)根據(jù)當(dāng)前工作線程的數(shù)量,如果wc > corePoolSize為false則當(dāng)前會(huì)被認(rèn)為是核心線程,調(diào)用workQueue.take()一直等待任務(wù)。
工作線程的關(guān)閉
還是在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) {
task.run();
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
- completedAbruptly變量:標(biāo)記當(dāng)前工作線程是正常執(zhí)行完成,還是異常完成的。completedAbruptly為
false可以確定線程池中沒(méi)有可執(zhí)行的任務(wù)了。
上面代碼是簡(jiǎn)潔后的代碼,一個(gè)while循環(huán)保證不間斷的獲取任務(wù),沒(méi)有任務(wù)可以執(zhí)行(task為null)退出循環(huán),最后再才會(huì)調(diào)用processWorkerExit方法:
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);
}
}
processWorkerExit接收一個(gè)Worker實(shí)例與completedAbruptly變量。processWorkerExit的大致工作流程:
- 判斷當(dāng)前工作線程是否異常完成,如果是直接減少工作線程的數(shù)量,簡(jiǎn)單的說(shuō)就是校正一下工作線程的數(shù)量。
- 增加完成的任務(wù)數(shù)量,將
Worker從workers中移除 - tryTerminate() 檢查線程池狀態(tài),因?yàn)榫€程池可以延遲關(guān)閉,如果你調(diào)用
shutdown方法后不會(huì)立即關(guān)閉,要等待所有的任務(wù)執(zhí)行完成,所以這里調(diào)用tryTerminate()方法,嘗試去調(diào)用terminated方法。
工作線程完成策略
如果某個(gè)工作線程完成,線程池內(nèi)部會(huì)判斷是否需要重新啟動(dòng)一個(gè):
//判斷線程池狀態(tài)
if (runStateLessThan(c, STOP)) {
if (!completedAbruptly) {
//獲取最小工作線程數(shù)量
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
//如果最小工作線程數(shù)量為0,但是workQueue中還有任務(wù),那重置最小工作線程數(shù)量1
if (min == 0 && ! workQueue.isEmpty())
min = 1;
//如果當(dāng)前工作線程數(shù)數(shù)量大于或等于最小工作線程數(shù)量,則不需要啟動(dòng)新的工作線程
if (workerCountOf(c) >= min)
return; // replacement not needed
}
//啟動(dòng)一個(gè)新的工作線程
addWorker(null, false);
}
工作線程完成后有兩種處理策略:
- 對(duì)于異常完成的工作線程,直接啟動(dòng)一個(gè)新的替換
- 對(duì)于正常完成的工作線程,判斷當(dāng)前工作線程是否足夠,如果足夠則不需要新啟動(dòng)工作線程
注意:這里的完成,表示工作線程的任務(wù)執(zhí)行完成,workQueue中也沒(méi)有任務(wù)可以獲取了。
線程池的關(guān)閉
關(guān)閉線程池有可以通過(guò)shutdown方法:
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
shutdown方法,第一步就是先改變線程池的狀態(tài),調(diào)用advanceRunState(SHUTDOWN)方法,將線程池當(dāng)前狀態(tài)更改為SHUTDOWN,advanceRunState代碼如下:
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
然后立即調(diào)用interruptIdleWorkers()方法,interruptIdleWorkers()內(nèi)部會(huì)調(diào)用它的重載方法interruptIdleWorkers(boolean onlyOne)同時(shí)onlyOne參數(shù)傳遞的false來(lái)關(guān)閉空閑的線程:
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
以上代碼會(huì)遍歷workers中的Worker實(shí)例,然后調(diào)用線程的interrupt()方法。
什么樣的線程才是空閑工作線程?
前面提到過(guò)在getTask()中,線程從workQueue中獲取任務(wù)時(shí)會(huì)阻塞,被阻塞的線程就是空閑的。
再次回到getTask()的代碼中:
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
// 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;
...
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
再次分析getTask()中的代碼中有一段捕獲InterruptedException的代碼塊,interruptIdleWorkers方法中斷線程后,getTask()會(huì)捕獲中斷異常,因?yàn)橥饷媸且粋€(gè)for循環(huán),隨后代碼走到判斷線程池狀態(tài)的地方:
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
decrementWorkerCount();
return null;
}
上面的代碼的會(huì)判斷當(dāng)前線程池狀態(tài),如果狀態(tài)大于STOP或者狀態(tài)等于SHUTDOWN并且workQueue為空時(shí)則返回null,getTask()返回空那么在runWorker中循環(huán)就會(huì)退出,當(dāng)前工作線程的任務(wù)就完成了,可以退出了:
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) {
task.run();
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
shutdownNow
除了shutdown方法能關(guān)閉線程池,還有shutdownNow也可以關(guān)閉線程池。它兩的區(qū)別在于:
-
shutdownNow會(huì)清空workQueue中的任務(wù) -
shutdownNow還會(huì)中止當(dāng)前正在運(yùn)行的任務(wù) -
shutdownNow會(huì)使線程進(jìn)入STOP狀態(tài),而shutdown()是SHUTDOWN狀態(tài)
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;
}
上面代碼基本流程:
- advanceRunState(STOP): 使線程池進(jìn)行
STOP狀態(tài),與shutdown()中的一致 ,只是使用的狀態(tài)碼是STOP - interruptWorkers(): 與
shutdown()中的一致 - drainQueue(): 清空隊(duì)列
任務(wù)是中止執(zhí)行還是繼續(xù)執(zhí)行?
調(diào)用shutdownNow()后線程池處于STOP狀態(tài),緊接著所有的工作線程都會(huì)被調(diào)用interrupt方法,如果此時(shí)runWorker還在運(yùn)行會(huì)發(fā)生什么?
在runWorker有一段代碼,就是工作線程中止的重要代碼:
final void runWorker(Worker w) {
...
while (task != null || (task = getTask()) != null) {
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
task.run();
}
...
}
重點(diǎn)關(guān)注:
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
這個(gè)if看起來(lái)有點(diǎn)難理解,理解下來(lái)大致意思是:如果線程池狀態(tài)大于等于STOP,立即中斷線程,否則清除線程的中斷標(biāo)記,也就是說(shuō)當(dāng)線程池狀態(tài)為RUNNING和SHUTDOWN時(shí),線程的中斷標(biāo)記會(huì)被清除(線程的中斷代碼在interruptWorkers方法中),可以繼續(xù)執(zhí)行任務(wù)。
以上代碼執(zhí)行完成后,緊接著就會(huì)調(diào)用task.run()方法,這里面我們自己就可以根據(jù)線程的中斷標(biāo)記來(lái)判斷任務(wù)是否被中斷。
總結(jié)
個(gè)人水平有限,文中如有錯(cuò)誤,謝謝大家指正。
本文從線程池的源碼入手,分析線程池的創(chuàng)建、添加任務(wù)、運(yùn)行任務(wù)等流程,整個(gè)分析下來(lái)基本上大多數(shù)公司關(guān)于線程池面試的問(wèn)題都可以回答得上來(lái),當(dāng)然還有一些小細(xì)節(jié)如:Worker類是繼承AQS的,為什么這么做其實(shí)源碼中都有一些苗頭,Worker在運(yùn)行時(shí)會(huì)鎖住運(yùn)行的代碼塊,而shutdown在關(guān)閉空閑的Worker時(shí),首先就要去獲取Worker的同步鎖才能繼續(xù)操作,這樣才能安全的關(guān)閉工作線程。
歡迎關(guān)注我的公眾號(hào):架構(gòu)文摘,獲得獨(dú)家整理120G的免費(fèi)學(xué)習(xí)資源助力你的架構(gòu)師學(xué)習(xí)之路!
公眾號(hào)后臺(tái)回復(fù)
arch028獲取資料: