第一部分:ThreadPoolExecutor的繼承結構
根據上圖可以知道,ThreadPoolExecutor是繼承的AbstractExecutorService(抽象類)。再來看一下AbstractExecutorService的結構可以發現,AbstractExecutorService實現了ExecutorService,並且ExecutorService繼承Executor接口。
如下是Executor和ExecutorService接口中一些方法:
public interface Executor {
void execute(Runnable command);
}
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException;
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException;
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException;
<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;
}
可以簡單總結一下:Executor這個接口只有一個方法execute(Runnable command)(以Command Pattern(命令模式)的設計模式實現);在ExecutorService接口中一部分是和執行器生命週期相關的方法,而另一部分則是以各種方式提交要執行的任務的方法。像submit()就是提交任務的一個方法,在實現中做了適配的工作,無論參數是Runnable還是Callable,執行器都會正確執行。ExecutorService中,和生命週期相關的,聲明瞭5個方法:
- awaitTermination() 阻塞等待shutdown請求後所有線程終止,會有時間參數,超時和中斷也會令方法調用結束
- isShutdown() 通過ctl屬性判斷當前的狀態是否不是RUNNING狀態
- isTerminated() 通過ctl屬性判斷當前的狀態是否爲TERMINATED狀態
- shutdown() 關閉Executor,不再接受提交任務
- shutdownNow() 關閉Executor,不再接受提交任務,並且不再執行入隊列中的任務
可以看出來:AbstractExecutorService這個類是ExecutorService的一個抽象實現。其中,提交任務的各類方法已經給出了十分完整的實現。之所以抽象,是因爲和執行器本身生命週期相關的方法在此類中並未給出任何實現,需要子類擴展完善(模板方法設計模式)拿一個submit方法出來分析一下:
/**
* @throws RejectedExecutionException {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
從代碼可以看出實際上用到的是RunnableFuture的實現類FutureTask。但最終還是調用了execute()方法,在子類中實現。
在正式進入ThreadPoolExecutor源碼分析之前還需要補充一點的是:Executors(工廠方法設計模式)java.util.concurrent.Executors是個工具類,提供了很多靜態的工具方法。其中很多對於執行器來說就是初始化構建用的工廠方法。
- 重載實現的newFixedThreadPool()
- 重載實現的newSingleThreadExecutor()
- 重載實現的newCachedThreadPool()
- 重載實現的newSingleThreadScheduledExecutor()
- 重載實現的newScheduledThreadPool()
這些方法返回的ExecutorService對象最終都是由ThreadPoolExecutor實現的,根據不同的需求以不同的參數配置,或經過其它類包裝。其中,Executors中的一些內部類就是用來做包裝用的。Executors類中還有靜態的defaultThreadFactory()方法,當然也可以自己實現自定義的ThreadFactory。
第二部分:ThreadPoolExecutor源碼分析
下面正式進入ThreadPoolExecutor:(按照程序運行順序分析)
1、ThreadPoolExecutor的全參數構造方法:
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code 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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
根據註釋:
- corePoolSize 是線程池的核心線程數,通常線程池會維持這個線程數
- maximumPoolSize 是線程池所能維持的最大線程數
- keepAliveTime 和 unit 則分別是超額(空閒)線程的空閒存活時間數和時間單位
- workQueue 是提交任務到線程池的入隊列
- threadFactory 是線程池創建新線程的線程構造器
- handler 是當線程池不能接受提交任務的時候的處理策略
2、execute方法提交任務
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
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);
}
通過註釋:提交新任務的時候,如果沒達到核心線程數corePoolSize,則開闢新線程執行。如果達到核心線程數corePoolSize, 而隊列未滿,則放入隊列,否則開新線程處理任務,直到maximumPoolSize,超出則丟棄處理。同時判斷目前線程的狀態是不是RUNNING其他線程有可能調用了shutdown()或shutdownNow()方法,關閉線程池,導致目前線程的狀態不是RUNNING。在上面提交任務的時候,會出現開闢新的線程來執行,這會調用addWorker()方法。
3、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()))
return false;
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
}
}
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);
}
return workerStarted;
}
第一部分:第一段從第3行到第26行,是雙層無限循環,嘗試增加線程數到ctl變量,並且做一些比較判斷,如果超出線程數限定或者ThreadPoolExecutor的狀態不符合要求,則直接返回false,增加worker失敗。第二部分:從第28行開始到結尾,把firstTask這個Runnable對象傳給Worker構造方法,賦值給Worker對象的task屬性。Worker對象把自身(也是一個Runnable)封裝成一個Thread對象賦予Worker對象的thread屬性。鎖住整個線程池並實際增加worker到workers的HashSet對象當中。成功增加後開始執行t.start(),就是worker的thread屬性開始運行,實際上就是運行Worker對象的run方法。Worker的run()方法實際上調用了ThreadPoolExecutor的runWorker()方法。在看runWorker()之前先看一下Worker對象。
4、Worker對象
Worker是真正的任務,是由任務執行線程完成,它是ThreadPoolExecutor的核心。每個線程池中,有爲數不等的Worker對象,每個Worker對象中,包含一個需要立即執行的新任務和已經執行完成的任務數量,Worker本身,是一個Runnable對象,不是Thread對象它內部封裝一個Thread對象,用此對象執行本身的run方法,而這個Thread對象則由ThreadPoolExecutor提供的ThreadFactory對象創建新的線程。(將Worker和Thread分離的好處是,如果我們的業務代碼,需要對於線程池中的線程,賦予優先級、線程名稱、線程執行策略等其他控制時,可以實現自己的ThreadFactory進行擴展,無需繼承或改寫ThreadPoolExecutor。)
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
final Thread thread;
/** Initial task to run. Possibly null. */
Runnable firstTask;
/** Per-thread task counter */
volatile long completedTasks;
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
// Lock methods
//
// 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) {
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;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
它既實現了Runnable,同時也是一個AQS ( AbstractQueuedSynchronizer )。封裝了3樣東西,Runnable類的首個任務對象,執行的線程thread和完成的任務數(volatile)completedTasks。這個類還提供了interruptIfStarted()這樣一個方法,裏面做了(getState()>=0)的判斷。與此呼應,Worker的構造方法裏對state設置了-1,避免在線程執行前被停掉。注意:第一個需要執行的任務
當有新的任務需要調度,並且需要創建新的線程時,在構造函數中爲其賦值,此時新任務不放入任務緩存隊列目的是減少任務緩存隊列入隊和出隊的操作,提高調度性能(任務緩存隊列的入隊和出隊操作,會涉及鎖定和併發處理)。
5、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) {
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);
}
}
根據代碼順序看下來,其實很簡單。
- 線程開始執行前,需要對worker加鎖,完成一個任務後執行unlock()
- 在任務執行前後,執行beforeExecute()和afterExecute()方法
- 記錄任務執行中的異常後,繼續拋出
- 每個任務完成後,會記錄當前線程完成的任務數
- 當worker執行完一個任務的時候,包括初始任務firstTask,會調用getTask()繼續獲取任務,這個方法調用
- 線程退出,執行processWorkerExit(w, completedAbruptly)處理
6、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()實際上是從工作隊列(workQueue)中取提交進來的任務。這個workQueue是一個BlockingQueue,通常當隊列中沒有新任務的時候,則getTask()會阻塞。另外,還有定時阻塞這樣一段邏輯:如果從隊列中取任務是計時的,則用poll()方法,並設置等待時間爲keepAlive,否則調用阻塞方法take()。當poll()超時,則獲取到的任務爲null,timeOut設置爲 true。這段代碼也是放在一個for(;;)循環中,前面有判斷超時的語句,如果超時,則return
null。這意味着runWorker()方法的while循環結束,線程將退出,執行processWorkerExit()方法。
其中:
int wc = workerCountOf(c);
// Are workers subject to culling?
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
即判斷當前線程池的線程數是否超出corePoolSize,如果超出這個值並且空閒時間多於keepAlive則當前線程退出。另外一種情況就是allowCoreThreadTimeOut爲true,就是允許核心在空閒超時的情況下停掉。最後再來看一下線程池線程數的維護和線程的退出處理。
7、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);
}
}
這個方法最主要就是從workers的Set中remove掉一個多餘的線程。這個方法的第二個參數是判斷是否在runWorker()中正常退出了循環向下執行。當前如果不是,說明在執行任務的過程中出現了異常,completedAbruptly爲true,線程直接退出,需要直接對活動線程數減1 ;如果是正常退出則加鎖統計完成的任務數,並從workers這個集合中移除當前worker。執行tryTerminate(),這個方法後面會介紹,主要就是嘗試將線程池推向TERMINATED狀態。最後比較當前線程數是不是已經低於應有的線程數,如果這個情況發生,則添加無任務的空Worker到線程池中待命。以上,增加新的線程和剔除多餘的線程的過程大概就是如此,這樣線程池能保持額定的線程數,並彈性伸縮,保證系統的資源不至於過度消耗。以上,增加新的線程和剔除多餘的線程的過程大概就是如此,這樣線程池能保持額定的線程數,並彈性伸縮,保證系統的資源不至於過度消耗。
8、tryTerminate()方法
tryTerminate()的意義就在於嘗試進入終止狀態
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
}
}
當ctl中worker數字爲0時執行terminated()方法,否則等鎖中斷一個空閒的Worker,其中interruptIdleWorkers()就是來中斷線程的。空閒的worker主要是通過worker的tryLock()來確認的,因爲執行任務的worker互斥地鎖定對象。中斷worker導致線程退出,最終還會循環嘗試終止其它的空閒線程,直到整個ThreadPoolExecutor最後終結。到此爲止,從線程池的新建,提交任務,到結束,基本結束。
第三部分:ThreadPoolExecutor生命週期
下面來補充一下ThreadPoolExecutor生命週期中的一些重要方法的介紹:
1、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,這樣就不會再接收新的任務提交。對空閒線程進行中斷調用。最後檢查線程池線程是否爲0,並嘗試切換到TERMINATED狀態。2、ShutDownNow()方法
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;
}
主要所做的事情就是切換ThreadPoolExecutor到STOP狀態,中斷所有worker,並將任務隊列中的任務取出來,不再執行。最後嘗試修改狀態到TERMINATED。
shutdown()和shutdownNow()的區別:
shutdown()新的任務不會再被提交到線程池,但之前的都會依舊執行,通過中斷方式停止空閒的(根據沒有獲取鎖來確定)線程。
shutdownNow()則向所有正在執行的線程發出中斷信號以嘗試終止線程,並將工作隊列中的任務以列表方式的結果返回。
- 一個要將線程池推到SHUTDOWN狀態,一個將推到STOP狀態
- 並且對運行的線程處理方式不同,shutdown()只中斷空閒線程,而shutdownNow()會嘗試中斷所有活動線程
- 還有就是對隊列中的任務處理,shutdown()隊列中已有任務會繼續執行,而shutdownNow()會直接取出不被執行
-
相同的是都在最後嘗試將線程池推到TERMINATED狀態。
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();
}
}
阻塞等待shutdown請求後所有線程終止,會有時間參數,超時和中斷也會令方法調用結束。實際所做的就是Condition的定時await調用。用於狀態依賴的線程阻塞。
4、ThreadPoolExecutor生命週期的擴展點
在生命週期上,ThreadPoolExecutor爲擴展的類提供了一些擴展點,這是很好的設計,對擴展開放。其中聲明瞭如下protected的方法:
- beforeExecute() 在每個任務執行前做的處理
- afterExecute() 在每個任務執行後做的處理
- terminated() 在ThreadPoolExecutor到達TERMINATED狀態前所做的處理
- finalize() 有默認實現,直接調用shutdown(),以保證線程池對象回收
- onShutdown() 在shutdown()方法執行到最後時調用,在ScheduledThreadPoolExecutor類實現中用到了這個
- 擴展點,做一些任務隊列的清理操作。
當ThreadPoolExecutor執行任務的時候,如果線程池的線程已經飽和,並且任務隊列也已滿。那麼就會做丟棄處理,這也是execute()方法實現中的操作,源碼如下:
else if (!addWorker(command, false))
reject(command);
//方法調用
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
//RejectedExecutionHandler接口
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor);
}
RejectedExecutionHandler 其中只有rejectedExecution()一個方法。返回爲void,而參數一個是具體的Runnable任務,另一個則是被提交任務的ThreadPoolExecutor。ThreadPoolExecutor給出了4種基本策略的實現。分別是:
- CallerRunsPolicy
- AbortPolicy
- DiscardPolicy
- DiscardOldestPolicy
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();
}
}
}
/**
* A handler for rejected tasks that throws a
* {@code 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());
}
}
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
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) {
}
}
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
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.調用者執行策略(CallerRunsPolicy)
在這個策略實現中,任務還是會被執行,但線程池中不會開闢新線程,而是提交任務的線程來負責維護任務。會先判斷ThreadPoolExecutor對象的狀態,之後執行任務。這樣處理的一個好處,是讓caller線程運行任務,以推遲該線程進一步提交新任務有效的緩解了線程池對象飽和的情況。
2.廢棄終止(AbortPolicy)
不處理,而是拋出java.util.concurrent.RejectedExecutionException異常。
注意,處理這個異常的線程是執行execute()的調用者線程。
3. 直接丟棄(DiscardPolicy)
這個也是實現最簡單的類,其中的rejectedExecution()方法是空實現,即什麼也不做,那麼提交的任務將會被丟棄,而不做任何處理
4.丟棄最老(DiscardPolicy)
會丟棄掉一個任務,但是是隊列中最早的。注意,會先判斷ThreadPoolExecutor對象是否已經進入SHUTDOWN以後的狀態。之後取出隊列頭的任務並不做任何處理,即丟棄,再重新調用execute()方法提交新任務。
到此,本文結束。
本文參考:
http://www.molotang.com/articles/501.html
http://www.molotang.com/articles/514.html
http://www.molotang.com/articles/522.html
http://www.molotang.com/articles/526.html
http://www.molotang.com/articles/553.html