一、線程池狀態(tài)
ThreadPoolExecutor 是 JDK 中的線程池實(shí)現(xiàn),這個(gè)類實(shí)現(xiàn)了一個(gè)線程池需要的各個(gè)方法,它實(shí)現(xiàn)了任務(wù)提交、線程管理、監(jiān)控等等方法。
原理圖:

private final AtomicIntegerctl =new AtomicInteger(ctlOf(RUNNING, 0));
? ? // 這里 COUNT_BITS 設(shè)置為 29(32-3),意味著前三位用于存放線程狀態(tài),后29位用于存放線程數(shù)
// 很多初學(xué)者很喜歡在自己的代碼中寫很多 29 這種數(shù)字,或者某個(gè)特殊的字符串,然后分布在各個(gè)地方,這是非常糟糕的
? ? private static final int COUNT_BITS = Integer.SIZE -3;
? ? // 000 11111111111111111111111111111
// 這里得到的是 29 個(gè) 1,也就是說線程池的最大線程數(shù)是 2^29-1=536870911
// 以我們現(xiàn)在計(jì)算機(jī)的實(shí)際情況,這個(gè)數(shù)量還是夠用的
? ? private static final int CAPACITY? = (1 <
? ? // 我們說了,線程池的狀態(tài)存放在高 3 位中
// 運(yùn)算結(jié)果為 111跟29個(gè)0:111 00000000000000000000000000000
? ? private static final int RUNNING? ? = -1 <
? ? // 000 00000000000000000000000000000
? ? private static final int SHUTDOWN? =0 <
? ? // 001 00000000000000000000000000000
? ? private static final int STOP? ? ? =1 <
? ? // 010 00000000000000000000000000000
? ? private static final int TIDYING? ? =2 <
? ? // 011 00000000000000000000000000000
? ? private static final int TERMINATED =3 <
? ? // 將整數(shù) c 的低 29 位修改為 0,就得到了線程池的狀態(tài)
? ? private static int runStateOf(int c)? ? {return c & ~CAPACITY; }
// 將整數(shù) c 的高 3 為修改為 0,就得到了線程池中的線程數(shù)
? ? private static int workerCountOf(int c)? {return c &CAPACITY; }
private static int ctlOf(int rs, int wc) {return rs | wc; }
/*
* Bit field accessors that don't require unpacking ctl.
* These depend on the bit layout and on workerCount being never negative.
*/
? ? private static boolean runStateLessThan(int c, int s) {
return c < s;
? ? }
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
? ? }
private static boolean isRunning(int c) {
return c
? ? }

RUNNING:這個(gè)沒什么好說的,這是最正常的狀態(tài):接受新的任務(wù),處理等待隊(duì)列中的任務(wù)
SHUTDOWN:不接受新的任務(wù)提交,但是會(huì)繼續(xù)處理等待隊(duì)列中的任務(wù)
STOP:不接受新的任務(wù)提交,不再處理等待隊(duì)列中的任務(wù),中斷正在執(zhí)行任務(wù)的線程
TIDYING:所有的任務(wù)都銷毀了,workCount 為 0。線程池的狀態(tài)在轉(zhuǎn)換為 TIDYING 狀態(tài)時(shí),會(huì)執(zhí)行鉤子方法 terminated()
TERMINATED:terminated() 方法結(jié)束后,線程池的狀態(tài)就會(huì)變成這個(gè)
二、Worker對(duì)象設(shè)計(jì)
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
private static final long serialVersionUID =6138294804551838833L;
? ? // 這個(gè)是真正的線程,任務(wù)靠你啦
? ? final Threadthread;
? ? // 前面說了,這里的 Runnable 是任務(wù)。為什么叫 firstTask?因?yàn)樵趧?chuàng)建線程的時(shí)候,如果同時(shí)指定了
// 這個(gè)線程起來以后需要執(zhí)行的第一個(gè)任務(wù),那么第一個(gè)任務(wù)就是存放在這里的(線程可不止執(zhí)行這一個(gè)任務(wù))
// 當(dāng)然了,也可以為 null,這樣線程起來了,自己到任務(wù)隊(duì)列(BlockingQueue)中取任務(wù)(getTask 方法)就行了
? ? RunnablefirstTask;
? ? // 用于存放此線程完全的任務(wù)數(shù),注意了,這里用了 volatile,保證可見性
? ? volatile long completedTasks;
? ? // Worker 只有這一個(gè)構(gòu)造方法,傳入 firstTask,也可以傳 null
? ? Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
? ? ? ? this.firstTask = firstTask;
? ? ? ? // 調(diào)用 ThreadFactory 來創(chuàng)建一個(gè)新的線程
? ? ? ? this.thread = getThreadFactory().newThread(this);
? ? }
// 這里調(diào)用了外部類的 runWorker 方法
? ? public void run() {
runWorker(this);
? ? }
...// 其他幾個(gè)方法沒什么好看的,就是用 AQS 操作,來獲取這個(gè)線程的執(zhí)行權(quán),用了獨(dú)占鎖
}
三、execute
public void execute(Runnable command) {
if (command ==null)
throw new NullPointerException();
? ? // 前面說的那個(gè)表示 “線程池狀態(tài)” 和 “線程數(shù)” 的整數(shù)
? ? int c = ctl.get();
? ? // 如果當(dāng)前線程數(shù)少于核心線程數(shù),那么直接添加一個(gè) worker 來執(zhí)行任務(wù),
// 創(chuàng)建一個(gè)新的線程,并把當(dāng)前任務(wù) command 作為這個(gè)線程的第一個(gè)任務(wù)(firstTask)
? ? if (workerCountOf(c) < corePoolSize) {
// 添加任務(wù)成功,那么就結(jié)束了。提交任務(wù)嘛,線程池已經(jīng)接受了這個(gè)任務(wù),這個(gè)方法也就可以返回了
// 至于執(zhí)行的結(jié)果,到時(shí)候會(huì)包裝到 FutureTask 中。
// 返回 false 代表線程池不允許提交任務(wù)
? ? ? ? if (addWorker(command, true))
return;
? ? ? ? c = ctl.get();
? ? }
// 到這里說明,要么當(dāng)前線程數(shù)大于等于核心線程數(shù),要么剛剛 addWorker 失敗了
// 如果線程池處于 RUNNING 狀態(tài),把這個(gè)任務(wù)添加到任務(wù)隊(duì)列 workQueue 中
? ? if (isRunning(c) && workQueue.offer(command)) {
/* 這里面說的是,如果任務(wù)進(jìn)入了 workQueue,我們是否需要開啟新的線程
* 因?yàn)榫€程數(shù)在 [0, corePoolSize) 是無條件開啟新的線程
* 如果線程數(shù)已經(jīng)大于等于 corePoolSize,那么將任務(wù)添加到隊(duì)列中,然后進(jìn)到這里
*/
? ? ? ? int recheck = ctl.get();
? ? ? ? // 如果線程池已不處于 RUNNING 狀態(tài),那么移除已經(jīng)入隊(duì)的這個(gè)任務(wù),并且執(zhí)行拒絕策略
? ? ? ? if (! isRunning(recheck) && remove(command))
reject(command);
? ? ? ? ? ? // 如果線程池還是 RUNNING 的,并且線程數(shù)為 0,那么開啟新的線程
// 到這里,我們知道了,這塊代碼的真正意圖是:擔(dān)心任務(wù)提交到隊(duì)列中了,但是線程都關(guān)閉了
? ? ? ? else if (workerCountOf(recheck) ==0)
addWorker(null, false);
? ? }
// 如果 workQueue 隊(duì)列滿了,那么進(jìn)入到這個(gè)分支
// 以 maximumPoolSize 為界創(chuàng)建新的 worker,
// 如果失敗,說明當(dāng)前線程數(shù)已經(jīng)達(dá)到 maximumPoolSize,執(zhí)行拒絕策略
? ? else if (!addWorker(command, false))
reject(command);
}
四、添加任務(wù)
// 第一個(gè)參數(shù)是準(zhǔn)備提交給這個(gè)線程執(zhí)行的任務(wù),之前說了,可以為 null
// 第二個(gè)參數(shù)為 true 代表使用核心線程數(shù) corePoolSize 作為創(chuàng)建線程的界線,也就說創(chuàng)建這個(gè)線程的時(shí)候,
//? ? ? ? 如果線程池中的線程總數(shù)已經(jīng)達(dá)到 corePoolSize,那么不能響應(yīng)這次創(chuàng)建線程的請(qǐng)求
//? ? ? ? 如果是 false,代表使用最大線程數(shù) maximumPoolSize 作為界線
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
? ? ? ? int rs = runStateOf(c);
? ? ? ? // 這個(gè)非常不好理解
// 如果線程池已關(guān)閉,并滿足以下條件之一,那么不創(chuàng)建新的 worker:
// 1. 線程池狀態(tài)大于 SHUTDOWN,其實(shí)也就是 STOP, TIDYING, 或 TERMINATED
// 2. firstTask != null
// 3. workQueue.isEmpty()
// 簡單分析下:
// 還是狀態(tài)控制的問題,當(dāng)線程池處于 SHUTDOWN 的時(shí)候,不允許提交任務(wù),但是已有的任務(wù)繼續(xù)執(zhí)行
// 當(dāng)狀態(tài)大于 SHUTDOWN 時(shí),不允許提交任務(wù),且中斷正在執(zhí)行的任務(wù)
// 多說一句:如果線程池處于 SHUTDOWN,但是 firstTask 為 null,且 workQueue 非空,那么是允許創(chuàng)建 worker 的
? ? ? ? if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask ==null &&
! workQueue.isEmpty()))
return false;
? ? ? ? for (;;) {
int wc = workerCountOf(c);
? ? ? ? ? ? if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
? ? ? ? ? ? // 如果成功,那么就是所有創(chuàng)建線程前的條件校驗(yàn)都滿足了,準(zhǔn)備創(chuàng)建線程執(zhí)行任務(wù)了
// 這里失敗的話,說明有其他線程也在嘗試往線程池中創(chuàng)建線程
? ? ? ? ? ? if (compareAndIncrementWorkerCount(c))
break retry;
? ? ? ? ? ? // 由于有并發(fā),重新再讀取一下 ctl
? ? ? ? ? ? c = ctl.get();
? ? ? ? ? ? // 正常如果是 CAS 失敗的話,進(jìn)到下一個(gè)里層的for循環(huán)就可以了
// 可是如果是因?yàn)槠渌€程的操作,導(dǎo)致線程池的狀態(tài)發(fā)生了變更,如有其他線程關(guān)閉了這個(gè)線程池
// 那么需要回到外層的for循環(huán)
? ? ? ? ? ? if (runStateOf(c) != rs)
continue retry;
? ? ? ? ? ? // else CAS failed due to workerCount change; retry inner loop
? ? ? ? }
}
/*
* 到這里,我們認(rèn)為在當(dāng)前這個(gè)時(shí)刻,可以開始創(chuàng)建線程來執(zhí)行任務(wù)了,
* 因?yàn)樵撔r?yàn)的都校驗(yàn)了,至于以后會(huì)發(fā)生什么,那是以后的事,至少當(dāng)前是滿足條件的
*/
// worker 是否已經(jīng)啟動(dòng)
? ? boolean workerStarted =false;
? ? // 是否已將這個(gè) worker 添加到 workers 這個(gè) HashSet 中
? ? boolean workerAdded =false;
? ? Worker w =null;
? ? try {
final ReentrantLock mainLock =this.mainLock;
? ? ? ? // 把 firstTask 傳給 worker 的構(gòu)造方法
? ? ? ? w =new Worker(firstTask);
? ? ? ? // 取 worker 中的線程對(duì)象,之前說了,Worker的構(gòu)造方法會(huì)調(diào)用 ThreadFactory 來創(chuàng)建一個(gè)新的線程
? ? ? ? final Thread t = w.thread;
? ? ? ? if (t !=null) {
// 這個(gè)是整個(gè)類的全局鎖,持有這個(gè)鎖才能讓下面的操作“順理成章”,
// 因?yàn)殛P(guān)閉一個(gè)線程池需要這個(gè)鎖,至少我持有鎖的期間,線程池不會(huì)被關(guān)閉
? ? ? ? ? ? mainLock.lock();
? ? ? ? ? ? try {
int c = ctl.get();
? ? ? ? ? ? ? ? int rs = runStateOf(c);
? ? ? ? ? ? ? ? // 小于 SHUTTDOWN 那就是 RUNNING,這個(gè)自不必說,是最正常的情況
// 如果等于 SHUTDOWN,前面說了,不接受新的任務(wù),但是會(huì)繼續(xù)執(zhí)行等待隊(duì)列中的任務(wù)
? ? ? ? ? ? ? ? if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask ==null)) {
// worker 里面的 thread 可不能是已經(jīng)啟動(dòng)的
? ? ? ? ? ? ? ? ? ? if (t.isAlive())
throw new IllegalThreadStateException();
? ? ? ? ? ? ? ? ? ? // 加到 workers 這個(gè) HashSet 中
? ? ? ? ? ? ? ? ? ? workers.add(w);
? ? ? ? ? ? ? ? ? ? int s = workers.size();
? ? ? ? ? ? ? ? ? ? // largestPoolSize 用于記錄 workers 中的個(gè)數(shù)的最大值
// 因?yàn)?workers 是不斷增加減少的,通過這個(gè)值可以知道線程池的大小曾經(jīng)達(dá)到的最大值
? ? ? ? ? ? ? ? ? ? if (s > largestPoolSize)
largestPoolSize = s;
? ? ? ? ? ? ? ? ? ? workerAdded =true;
? ? ? ? ? ? ? ? }
}finally {
mainLock.unlock();
? ? ? ? ? ? }
// 添加成功的話,啟動(dòng)這個(gè)線程
? ? ? ? ? ? if (workerAdded) {
// 啟動(dòng)線程
? ? ? ? ? ? ? ? t.start();
? ? ? ? ? ? ? ? workerStarted =true;
? ? ? ? ? ? }
}
}finally {
// 如果線程沒有啟動(dòng),需要做一些清理工作,如前面 workCount 加了 1,將其減掉
? ? ? ? if (! workerStarted)
addWorkerFailed(w);
? ? }
// 返回線程是否啟動(dòng)成功
? ? return workerStarted;
}
五、執(zhí)行任務(wù)
// 此方法由 worker 線程啟動(dòng)后調(diào)用,這里用一個(gè) while 循環(huán)來不斷地從等待隊(duì)列中獲取任務(wù)并執(zhí)行
// 前面說了,worker 在初始化的時(shí)候,可以指定 firstTask,那么第一個(gè)任務(wù)也就可以不需要從隊(duì)列中獲取
final void runWorker(Worker w) {
//
? ? Thread wt = Thread.currentThread();
? ? // 該線程的第一個(gè)任務(wù)(如果有的話)
? ? Runnable task = w.firstTask;
? ? w.firstTask =null;
? ? w.unlock(); // allow interrupts
? ? boolean completedAbruptly =true;
? ? try {
// 循環(huán)調(diào)用 getTask 獲取任務(wù)
? ? ? ? while (task !=null || (task = getTask()) !=null) {
w.lock();
? ? ? ? ? ? // 如果線程池狀態(tài)大于等于 STOP,那么意味著該線程也要中斷
? ? ? ? ? ? if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
? ? ? ? ? ? try {
// 這是一個(gè)鉤子方法,留給需要的子類實(shí)現(xiàn)
? ? ? ? ? ? ? ? beforeExecute(wt, task);
? ? ? ? ? ? ? ? Throwable thrown =null;
? ? ? ? ? ? ? ? try {
// 到這里終于可以執(zhí)行任務(wù)了
? ? ? ? ? ? ? ? ? ? task.run();
? ? ? ? ? ? ? ? }catch (RuntimeException x) {
thrown = x; throw x;
? ? ? ? ? ? ? ? }catch (Error x) {
thrown = x; throw x;
? ? ? ? ? ? ? ? }catch (Throwable x) {
// 這里不允許拋出 Throwable,所以轉(zhuǎn)換為 Error
? ? ? ? ? ? ? ? ? ? thrown = x; throw new Error(x);
? ? ? ? ? ? ? ? }finally {
// 也是一個(gè)鉤子方法,將 task 和異常作為參數(shù),留給需要的子類實(shí)現(xiàn)
? ? ? ? ? ? ? ? ? ? afterExecute(task, thrown);
? ? ? ? ? ? ? ? }
}finally {
// 置空 task,準(zhǔn)備 getTask 獲取下一個(gè)任務(wù)
? ? ? ? ? ? ? ? task =null;
? ? ? ? ? ? ? ? // 累加完成的任務(wù)數(shù)
? ? ? ? ? ? ? ? w.completedTasks++;
? ? ? ? ? ? ? ? // 釋放掉 worker 的獨(dú)占鎖
? ? ? ? ? ? ? ? w.unlock();
? ? ? ? ? ? }
}
completedAbruptly =false;
? ? }finally {
// 如果到這里,需要執(zhí)行線程關(guān)閉:
// 1. 說明 getTask 返回 null,也就是說,這個(gè) worker 的使命結(jié)束了,執(zhí)行關(guān)閉
// 2. 任務(wù)執(zhí)行過程中發(fā)生了異常
// 第一種情況,已經(jīng)在代碼處理了將 workCount 減 1,這個(gè)在 getTask 方法分析中會(huì)說
// 第二種情況,workCount 沒有進(jìn)行處理,所以需要在 processWorkerExit 中處理
// 限于篇幅,我不準(zhǔn)備分析這個(gè)方法了,感興趣的讀者請(qǐng)自行分析源碼
? ? ? ? processWorkerExit(w, completedAbruptly);
? ? }
}
六、獲取任務(wù)
// 此方法有三種可能:
// 1. 阻塞直到獲取到任務(wù)返回。我們知道,默認(rèn) corePoolSize 之內(nèi)的線程是不會(huì)被回收的,
//? ? ? 它們會(huì)一直等待任務(wù)
// 2. 超時(shí)退出。keepAliveTime 起作用的時(shí)候,也就是如果這么多時(shí)間內(nèi)都沒有任務(wù),那么應(yīng)該執(zhí)行關(guān)閉
// 3. 如果發(fā)生了以下條件,此方法必須返回 null:
//? ? - 池中有大于 maximumPoolSize 個(gè) workers 存在(通過調(diào)用 setMaximumPoolSize 進(jìn)行設(shè)置)
//? ? - 線程池處于 SHUTDOWN,而且 workQueue 是空的,前面說了,這種不再接受新的任務(wù)
//? ? - 線程池處于 STOP,不僅不接受新的線程,連 workQueue 中的線程也不再執(zhí)行
private RunnablegetTask() {
boolean timedOut =false; // Did the last poll() time out?
? ? retry:
for (;;) {
int c = ctl.get();
? ? ? ? int rs = runStateOf(c);
? ? ? ? // 兩種可能
// 1. rs == SHUTDOWN && workQueue.isEmpty()
// 2. rs >= STOP
? ? ? ? if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// CAS 操作,減少工作線程數(shù)
? ? ? ? ? ? decrementWorkerCount();
return null;
? ? ? ? }
boolean timed;? ? ? // Are workers subject to culling?
? ? ? ? for (;;) {
int wc = workerCountOf(c);
? ? ? ? ? ? // 允許核心線程數(shù)內(nèi)的線程回收,或當(dāng)前線程數(shù)超過了核心線程數(shù),那么有可能發(fā)生超時(shí)關(guān)閉
? ? ? ? ? ? timed = allowCoreThreadTimeOut || wc > corePoolSize;
? ? ? ? ? ? // 這里 break,是為了不往下執(zhí)行后一個(gè) if (compareAndDecrementWorkerCount(c))
// 兩個(gè) if 一起看:如果當(dāng)前線程數(shù) wc > maximumPoolSize,或者超時(shí),都返回 null
// 那這里的問題來了,wc > maximumPoolSize 的情況,為什么要返回 null?
//? ? 換句話說,返回 null 意味著關(guān)閉線程。
// 那是因?yàn)橛锌赡荛_發(fā)者調(diào)用了 setMaximumPoolSize 將線程池的 maximumPoolSize 調(diào)小了
? ? ? ? ? ? if (wc <= maximumPoolSize && ! (timedOut && timed))
break;
? ? ? ? ? ? if (compareAndDecrementWorkerCount(c))
return null;
? ? ? ? ? ? c = ctl.get();? // Re-read ctl
// compareAndDecrementWorkerCount(c) 失敗,線程池中的線程數(shù)發(fā)生了改變
? ? ? ? ? ? if (runStateOf(c) != rs)
continue retry;
? ? ? ? ? ? // else CAS failed due to workerCount change; retry inner loop
? ? ? ? }
// wc <= maximumPoolSize 同時(shí)沒有超時(shí)
? ? ? ? try {
// 到 workQueue 中獲取任務(wù)
? ? ? ? ? ? Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
? ? ? ? ? ? if (r !=null)
return r;
? ? ? ? ? ? timedOut =true;
? ? ? ? }catch (InterruptedException retry) {
// 如果此 worker 發(fā)生了中斷,采取的方案是重試
// 解釋下為什么會(huì)發(fā)生中斷,這個(gè)讀者要去看 setMaximumPoolSize 方法,
// 如果開發(fā)者將 maximumPoolSize 調(diào)小了,導(dǎo)致其小于當(dāng)前的 workers 數(shù)量,
// 那么意味著超出的部分線程要被關(guān)閉。重新進(jìn)入 for 循環(huán),自然會(huì)有部分線程會(huì)返回 null
? ? ? ? ? ? timedOut =false;
? ? ? ? }
}
}
七、案例分析
ThreadPoolExecutor pool =new ThreadPoolExecutor(1,2,60, TimeUnit.SECONDS,new ArrayBlockingQueue<>(3));
MyTask task1 =new MyTask(1,"任務(wù)1");
MyTask task2 =new MyTask(2,"任務(wù)2");
MyTask task3 =new MyTask(3,"任務(wù)3");
MyTask task4 =new MyTask(4,"任務(wù)4");
MyTask task5 =new MyTask(5,"任務(wù)5");
pool.execute(task1);
pool.execute(task2);
pool.execute(task3);
pool.execute(task4);
pool.execute(task5);
八、總結(jié)
1.?線程池中的線程創(chuàng)建時(shí)機(jī)
如果當(dāng)前線程數(shù)少于 corePoolSize,那么提交任務(wù)的時(shí)候創(chuàng)建一個(gè)新的線程,并由這個(gè)線程執(zhí)行這個(gè)任務(wù);
如果當(dāng)前線程數(shù)已經(jīng)達(dá)到 corePoolSize,那么將提交的任務(wù)添加到隊(duì)列中,等待線程池中的線程去隊(duì)列中取任務(wù);
如果隊(duì)列已滿,那么創(chuàng)建新的線程來執(zhí)行任務(wù),需要保證池中的線程數(shù)不會(huì)超過 maximumPoolSize,如果此時(shí)線程數(shù)超過了 maximumPoolSize,那么執(zhí)行拒絕策略。
2. 關(guān)鍵屬性
corePoolSize 到 maximumPoolSize 之間的線程會(huì)被回收,當(dāng)然 corePoolSize 的線程也可以通過設(shè)置而得到回收(allowCoreThreadTimeOut(true))。
workQueue 用于存放任務(wù),添加任務(wù)的時(shí)候,如果當(dāng)前線程數(shù)超過了 corePoolSize,那么往該隊(duì)列中插入任務(wù),線程池中的線程會(huì)負(fù)責(zé)到隊(duì)列中拉取任務(wù)。
keepAliveTime 用于設(shè)置空閑時(shí)間,如果線程數(shù)超出了 corePoolSize,并且有些線程的空閑時(shí)間超過了這個(gè)值,會(huì)執(zhí)行關(guān)閉這些線程的操作
rejectedExecutionHandler 用于處理當(dāng)線程池不能執(zhí)行此任務(wù)時(shí)的情況,默認(rèn)有拋出 RejectedExecutionException 異常、忽略任務(wù)、使用提交任務(wù)的線程來執(zhí)行此任務(wù)和將隊(duì)列中等待最久的任務(wù)刪除,然后提交此任務(wù)這四種策略,默認(rèn)為拋出異常。