1. 閱讀Java線程池ThreadPoolExecutor源碼
1.1前言
線程池主要解決兩個問題:一方面當執行大量異步任務時候線程池能夠提供較好的性能,這是因爲使用線程池可以使每個任務的調用開銷減少(因爲線程池線程是可以複用的)。另一方面線程池提供了一種資源限制和管理的手段,比如當執行一系列任務時候對線程的管理,每個ThreadPoolExecutor也保留了一些基本的統計數據,比如當前線程池完成的任務數目。
另外,線程池提供許多可調參數和可擴展性鉤子。程序員可以使用更方便。工廠方法比如newCachedThreadPool(無限線程池,線程自動回收),newFixedThreadPool(固定大小的線程池)newSingleThreadExecutor(單個線程),當然用戶還可以自定義。
先來一張整體流程圖,看一下ThreadPoolExecutor的處理邏輯:
1.2線程池的若干狀態
/**
* The main pool control state, ctl, is an atomic integer packing
* two conceptual fields
* workerCount, indicating the effective number of threads
* runState, indicating whether running, shutting down etc
* 線程池主要的控制狀態值ctl是一個院子類型的整數值,它封裝了兩個概念上的域:
* workerCount:標識了當先有效的線程數
* runState:標識運行、關閉等狀態
*
* In order to pack them into one int, we limit workerCount to
* (2^29)-1 (about 500 million) threads rather than (2^31)-1 (2
* billion) otherwise representable. If this is ever an issue in
* the future, the variable can be changed to be an AtomicLong,
* and the shift/mask constants below adjusted. But until the need
* arises, this code is a bit faster and simpler using an int.
*
* 爲了將這兩個變量封裝到一個整型數值中,我們限制了 workerCount的上限在(2^29)-1(大約
* 5億左右)而不是(2^31)-1(20億左右)。如果整型值在未來是個問題,整型值可以替換成
* 原子類型長整型,位移/掩碼變量可以隨之調整。但是除非是需求上漲,否則用int會更快更簡單些。
*
* The workerCount is the number of workers that have been
* permitted to start and not permitted to stop. The value may be
* transiently different from the actual number of live threads,
* for example when a ThreadFactory fails to create a thread when
* asked, and when exiting threads are still performing
* bookkeeping before terminating. The user-visible pool size is
* reported as the current size of the workers set.
*
* workerCount是允許運行並且不允許停止的工作線程數。該值可能與實際活躍線程的數量不同。
* 比如線程工廠創建線程失敗且線程在終止之前人執行簿記工作。用戶可見的線程池大小是當前工作線程集合打大小
*
* The runState provides the main lifecyle control, taking on values:
* 運行狀態提供了主要的生命週期控制,接受一下值:
*
* RUNNING: Accept new tasks and process queued tasks
* SHUTDOWN: Don't accept new tasks, but process queued tasks
* STOP: Don't accept new tasks, don't process queued tasks,
* and interrupt in-progress tasks
* TIDYING: All tasks have terminated, workerCount is zero,
* the thread transitioning to state TIDYING
* will run the terminated() hook method
* TERMINATED: terminated() has completed
*
* RUNNING:接受新任務並處理隊列中的任務
* SHUTDOWN:不接受新任務,但是處理隊列中的任務
* STOP:不接受新的任務,也不會處理隊列中的任務,並且會中斷處理中的任務
* TIDYING:所有的任務終止,workerCount=0,線程過度到TIDYING狀態將會執行terminated()
* 鉤子函數。
*
*
* The numerical order among these values matters, to allow
* ordered comparisons. The runState monotonically increases over
* time, but need not hit each state. The transitions are:
*
* 這些值之間的數值順序很重要,可以進行排序比較。運行狀態單調地隨時間增加,但不需要對經歷所有狀態。
*
* RUNNING -> SHUTDOWN
* On invocation of shutdown(), perhaps implicitly in finalize()
* 調用shutdown方法或者隱式的調用finalize方法
*
* (RUNNING or SHUTDOWN) -> STOP
* On invocation of shutdownNow()
* 調用shutdownNow方法的時候
*
* SHUTDOWN -> TIDYING
* When both queue and pool are empty
* 隊列和線程池都爲空的時候
*
* STOP -> TIDYING
* When pool is empty
* 線程池爲空
*
* TIDYING -> TERMINATED
* When the terminated() hook method has completed
* terminated()鉤子函數執行完成
*
* Threads waiting in awaitTermination() will return when the
* state reaches TERMINATED.
*
* Detecting the transition from SHUTDOWN to TIDYING is less
* straightforward than you'd like because the queue may become
* empty after non-empty and vice versa during SHUTDOWN state, but
* we can only terminate if, after seeing that it is empty, we see
* that workerCount is 0 (which sometimes entails a recheck -- see
* below).
* 探測狀態從SHUTDOWN到TIDYING可能並不想你想象的直接,因爲隊列可能在非空狀態後又變成空隊列,
* 反之亦然。只有在看到它是空的之後,我們纔可以終止,我們看到,workerCount是0
*/
//一個變量存儲線程池狀態 和 線程池線程個數兩個信息。
//初始狀態:ctl = 111100000,00000000,00000000,00000000
//用來標記線程池狀態(高3位),線程個數(低29位)默認是RUNNING狀態,線程個數爲0
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//COUNT_BITS = 29,線程個數掩碼位數
private static final int COUNT_BITS = Integer.SIZE - 3;
//線程最大個數,CAPACITY = 00011111,11111111,11111111,11111111
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
//運行狀態保存在高位
//高3位是111,RUNNING = 111100000,00000000,00000000,00000000
//接受新任務並且處理阻塞隊列裏的任務
private static final int RUNNING = -1 << COUNT_BITS;
//高3位是000,SHUTDOWN = 00000000,00000000,00000000,00000000
//拒絕新任務但是處理阻塞隊列裏的任務
private static final int SHUTDOWN = 0 << COUNT_BITS;
//高3位是001,STOP = 00100000,00000000,00000000,00000000
//拒絕新任務並且拋棄阻塞隊列裏的任務同時會中斷正在處理的任務
private static final int STOP = 1 << COUNT_BITS;
//高3位是010,TIDYING = 01000000,00000000,00000000,00000000
//所有任務都執行完(包含阻塞隊列裏任務)當前線程池活動線程爲0,將要調用terminated方法
private static final int TIDYING = 2 << COUNT_BITS;
//高3位是011,TERMINATED = 01100000,00000000,00000000,00000000
//終止狀態。terminated方法調用完成以後的狀態
private static final int TERMINATED = 3 << COUNT_BITS;
1.3有關運行狀態的操作
/**
* 獲取高三位當前線程池的狀態
* c和~CAPACITY做與運算
* ~CAPACITY = 11100000,00000000,00000000,00000000
* c和~CAPACITY做與操作,導致c的最高3位保留,c的低29位爲0
* 也就是上面定義的幾種狀態RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED
* @param c
* @return
*/
private static int runStateOf(int c) { return c & ~CAPACITY; }
// c與CAPACITY做與運算,得到c的低29位二進制,也就是工作線程數
private static int workerCountOf(int c) { return c & CAPACITY; }
//rs和wc做或運算,計算ctl新值
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.
*
* 不需要拆包的位字段訪問器。這依賴於位的佈局和workerCount永遠不會是一個負數。
*/
//運行狀態小於s
private static boolean runStateLessThan(int c, int s) {
return c < s;
}
//運行狀態不小於s
private static boolean runStateAtLeast(int c, int s) {
return c >= s;
}
//當前線程數是否小於0,小於0表示運行狀態
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
/**
* Attempt to CAS-increment the workerCount field of ctl.
* 嘗試使用CAS的增加ctl中維護的workerCount域的值
*/
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
}
/**
* Attempt to CAS-decrement the workerCount field of ctl.
* 嘗試使用CAS的減少ctl中維護的workerCount域的值
*/
private boolean compareAndDecrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect - 1);
}
/**
* Decrements the workerCount field of ctl. This is called only on
* abrupt termination of a thread (see processWorkerExit). Other
* decrements are performed within getTask.
*
* 減少ctl的工作線程數。此方法只有在線程突然中止的時候調用(詳情參見processWorkerExit)
* 其他情況減少線程數在getTask中執行
*/
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
1.4阻塞隊列
/**
* The queue used for holding tasks and handing off to worker
* threads. We do not require that workQueue.poll() returning
* null necessarily means that workQueue.isEmpty(), so rely
* solely on isEmpty to see if the queue is empty (which we must
* do for example when deciding whether to transition from
* SHUTDOWN to TIDYING). This accommodates special-purpose
* queues such as DelayQueues for which poll() is allowed to
* return null even if it may later return non-null when delays
* expire.
*
* 用於保存任務並將其傳遞給工作線程的隊列。不用workQueue.poll()返回null來判斷隊列
* 爲空,僅僅根據isEmpty就 可以知道隊列是否爲空。(這是決定是否要將狀態從SHUTDOWN
* 轉變到TIDYING必須要檢查的)。此隊列滿足特殊目的的隊列,如即使在稍後會返回非空值,但是
* 本次在延遲超時之後,可以從poll方法返回null的DelayQueues。
*/
private final BlockingQueue<Runnable> workQueue;
1.5重入鎖
/**
* Lock held on access to workers set and related bookkeeping.
* While we could use a concurrent set of some sort, it turns out
* to be generally preferable to use a lock. Among the reasons is
* that this serializes interruptIdleWorkers, which avoids
* unnecessary interrupt storms, especially during shutdown.
* Otherwise exiting threads would concurrently interrupt those
* that have not yet interrupted. It also simplifies some of the
* associated statistics bookkeeping of largestPoolSize etc. We
* also hold mainLock on shutdown and shutdownNow, for the sake of
* ensuring workers set is stable while separately checking
* permission to interrupt and actually interrupting.
*
* 訪問工作線程集合和相關簿記工作持有的鎖。雖然我爲了們可以使用某種類型的併發集,但通常情況下,
* 使用鎖是比較可取的。其中的一個原因就是,這些連續的interruptIdleWorkers,尤其
* 是在關閉關閉期間,避免了不必要的中斷。然而線程退出將併發中斷尚未中斷的線程。它也簡化了
* largestPoolSize的相關的統計操作。在檢查中斷,和實際中斷操作權限時,爲了確保工作線程集是穩定,
* 我們在執行shutdown和shutdownNow時也持有mainLock鎖。
*/
private final ReentrantLock mainLock = new ReentrantLock();
1.6線程集合
/**
* Set containing all worker threads in pool. Accessed only when
* holding mainLock.
* 池中維護所有工作線程的Set集合。只能在持有mainLock鎖的時候才能訪問。
*/
private final HashSet<java.util.concurrent.ThreadPoolExecutor.Worker> workers = new HashSet<java.util.concurrent.ThreadPoolExecutor.Worker>();
1.7線程池參數
/**
* Wait condition to support awaitTermination
* 等待條件以支持awaitTermination
*/
private final Condition termination = mainLock.newCondition();
/**
* Tracks largest attained pool size. Accessed only under
* mainLock.
*
* 記錄達到的最大的線程數,只能在mainLock鎖保護下訪問
*/
private int largestPoolSize;
/**
* Counter for completed tasks. Updated only on termination of
* worker threads. Accessed only under mainLock.
*
* 完成的任務計數器。只有在工作線程終止的時候更新。必須在mainLock保護下訪問
*/
private long completedTaskCount;
/*
* All user control parameters are declared as volatiles so that
* ongoing actions are based on freshest values, but without need
* for locking, since no internal invariants depend on them
* changing synchronously with respect to other actions.
*
* 所有用戶控制的參數都被聲明爲volatile,這樣正在進行中的操作都是基於最新的值的,但是沒有必要
* 加鎖,因爲沒有內部的變量依賴於它們在其他操作上的同步變化。
*/
/**
* Factory for new threads. All threads are created using this
* factory (via method addWorker). All callers must be prepared
* for addWorker to fail, which may reflect a system or user's
* policy limiting the number of threads. Even though it is not
* treated as an error, failure to create threads may result in
* new tasks being rejected or existing ones remaining stuck in
* the queue.
*
* 創建新線程的工廠。所有都是用這個工廠創建的。(通過addWorker方法)所有調用者必須爲addWorker
* 失敗做好準備,這可能反應了系統或用戶限制線程數量的策略。儘管創建新線程失敗不會被當成是錯誤,
* 但是創建失敗可能會導致新任務被拒絕或者現有線程被阻塞在隊列中不能被執行。
*
* We go further and preserve pool invariants even in the face of
* errors such as OutOfMemoryError, that might be thrown while
* trying to create threads. Such errors are rather common due to
* the need to allocate a native stack in Thread#start, and users
* will want to perform clean pool shutdown to clean up. There
* will likely be enough memory available for the cleanup code to
* complete without encountering yet another OutOfMemoryError.
*
* 即使在創建新線程時,面臨像OutOfMemoryError的錯誤,我們也會進一步維護池不變量。由於
* 因爲要爲Thread的start分配native stack空間,這些錯誤是正常的,用戶將執行清理線程池。
* 在不遇到另一個OutOfMemoryError錯誤的情況下,可能有足夠的內存可用來完成清理代碼。
*
*/
private volatile ThreadFactory threadFactory;
/**
* Handler called when saturated or shutdown in execute.
* Handler在線程池飽和或者關閉的時候調用
*/
private volatile RejectedExecutionHandler handler;
/**
* Timeout in nanoseconds for idle threads waiting for work.
* Threads use this timeout when there are more than corePoolSize
* present or if allowCoreThreadTimeOut. Otherwise they wait
* forever for new work.
*
* 空閒線程等待任務超時時間,單位是納秒。當現有的線程數超過corePoolSize或者
* allowCoreThreadTimeOut爲true,線程將會使用這個超時時間。否則線程將
* 永遠等待新任務的到來。
*
*/
private volatile long keepAliveTime;
/**
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
* 如果爲false(默認),在空閒的時候核心線程儘管也會保持活躍。如果爲true,那麼核心線程將
* 在keepAliveTime的超時時間內等待新任務。
*/
private volatile boolean allowCoreThreadTimeOut;
/**
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
*
* 不允許線程超時的情況,線程池核心線程個數是最小的活躍的工作線程數,否則,核心線程數最小值爲0
*
*/
private volatile int corePoolSize;
/**
* Maximum pool size. Note that the actual maximum is internally
* bounded by CAPACITY.
*
* 線程池最大線程數。注意,實際的最大值在內部是由容量限制的。
*/
private volatile int maximumPoolSize;
/**
* The default rejected execution handler
*
* 默認的拒絕執行策略
*/
private static final RejectedExecutionHandler defaultHandler =
new java.util.concurrent.ThreadPoolExecutor.AbortPolicy();
/**
* Permission required for callers of shutdown and shutdownNow.
* We additionally require (see checkShutdownAccess) that callers
* have permission to actually interrupt threads in the worker set
* (as governed by Thread.interrupt, which relies on
* ThreadGroup.checkAccess, which in turn relies on
* SecurityManager.checkAccess). Shutdowns are attempted only if
* these checks pass.
*
* 調用shutdown和shutdownNow需要的權限。我們也要求調用者有權限去中斷線程集合中的線程。
* (Thread.interrupt依賴ThreadGroup.checkAccess,反過來又依賴於
* SecurityManager.checkAccess)關閉線程只能在權限校驗通過才能執行。
*
* All actual invocations of Thread.interrupt (see
* interruptIdleWorkers and interruptWorkers) ignore
* SecurityExceptions, meaning that the attempted interrupts
* silently fail. In the case of shutdown, they should not fail
* unless the SecurityManager has inconsistent policies, sometimes
* allowing access to a thread and sometimes not. In such cases,
* failure to actually interrupt threads may disable or delay full
* termination. Other uses of interruptIdleWorkers are advisory,
* and failure to actually interrupt will merely delay response to
* configuration changes so is not handled exceptionally.
*
* 所有對Thread.interrupt方法的調用都忽略了安全異常。這就意味着嘗試中斷會無聲的中斷。
* 在關閉的情況下,除非SecurityManager具有不一致的策略,否則它們不應該失敗,
* 有時允許訪問線程,有時不允許訪問。這種情況下,如果不能真正中斷線程,可能會緊張或延遲
* 完全終止。中斷服務的其他用途是諮詢性的,而實際上的中斷只會延遲對配置更改的響應,所以不處理異常
*/
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
/**
* Permission required for callers of shutdown and shutdownNow.
* We additionally require (see checkShutdownAccess) that callers
* have permission to actually interrupt threads in the worker set
* (as governed by Thread.interrupt, which relies on
* ThreadGroup.checkAccess, which in turn relies on
* SecurityManager.checkAccess). Shutdowns are attempted only if
* these checks pass.
*
* 調用shutdown和shutdownNow需要的權限。我們也要求調用者有權限去中斷線程集合中的線程。
* (Thread.interrupt依賴ThreadGroup.checkAccess,反過來又依賴於
* SecurityManager.checkAccess)關閉線程只能在權限校驗通過才能執行。
*
* All actual invocations of Thread.interrupt (see
* interruptIdleWorkers and interruptWorkers) ignore
* SecurityExceptions, meaning that the attempted interrupts
* silently fail. In the case of shutdown, they should not fail
* unless the SecurityManager has inconsistent policies, sometimes
* allowing access to a thread and sometimes not. In such cases,
* failure to actually interrupt threads may disable or delay full
* termination. Other uses of interruptIdleWorkers are advisory,
* and failure to actually interrupt will merely delay response to
* configuration changes so is not handled exceptionally.
*
* 所有對Thread.interrupt方法的調用都忽略了安全異常。這就意味着嘗試中斷會無聲的失敗。
* 在關閉的情況下,除非SecurityManager具有不一致的策略,否則它們不應該失敗,
* 有時允許訪問線程,有時不允許訪問。這種情況下,如果不能真正中斷線程,可能會阻止或延遲
* 完全終止。interruptIdleWorkers的其他用途是諮詢性的,而實際上的中斷只會延遲對配置更改的響應,
* 所以不處理異常
*/
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
1.8構造函數
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory and rejected execution handler.
* It may be more convenient to use one of the {@link Executors} factory
* methods instead of this general purpose constructor.
* 用給定參數和默認的線程工廠和拒絕策略創建一個新線程池。用Executors類的工廠方法可以比此構造器更加方便實現創建線程池。
*
* @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.
* @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} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default rejected execution handler.
* 用給定參數和默認的線程和默認的拒絕策略創建一個新線程池。
*
* @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
* @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} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory.
* 用給定的參數和默認的線程工廠創建一個新線程池。
* @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 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 handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
/**
* 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;
}
下面來看看Executors中的線程工廠:
newFixedThreadPool
創建一個核心線程個數和最大線程個數都爲nThreads的線程池,並且阻塞隊列長度爲Integer.MAX_VALUE,keeyAliveTime=0說明只要線程個數比核心線程個數多並且當前空閒則回收。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
newSingleThreadExecutor
創建一個核心線程個數和最大線程個數都爲1的線程池,並且阻塞隊列長度爲Integer.MAX_VALUE,keeyAliveTime=0說明只要線程個數比核心線程個數多並且當前空閒則回收。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newSingleThreadExecutor(ThreadFactory threadFactory) {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory));
}
newCachedThreadPool
創建一個按需創建線程的線程池,初始線程個數爲0,最多線程個數爲Integer.MAX_VALUE,並且阻塞隊列爲同步隊列,keeyAliveTime=60說明只要當前線程60s內空閒則回收。這個特殊在於加入到同步隊列的任務會被馬上被執行,同步隊列裏面最多隻有一個任務,並且存在後馬上會拿出執行。
public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>(),
threadFactory);
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
newSingleThreadScheduledExecutor
創建一個最小線程個數corePoolSize爲1,最大爲Integer.MAX_VALUE,阻塞隊列爲DelayedWorkQueue的線程池。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
newScheduledThreadPool
創建一個最小線程個數corePoolSize,最大爲Integer.MAX_VALUE,阻塞隊列爲DelayedWorkQueue的線程池。
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
1.9添加任務到線程池exectue方法
/**
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
* 在未來某個時間點執行給定的任務。該任務可能在新的線程
* 或者在現有的池中執行
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {@code RejectedExecutionHandler}.
* 如果因爲執行器被關閉或者執行器打到了最大容量而導致任務不能被
* 提交執行,該任務將由當前的RejectedExecutionHandler進行處理
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* {@code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* @throws NullPointerException if {@code command} is null
*/
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.
* 1.如果線程數小於正在運行的corePoolSize線程數,首要任務
* 是嘗試使用給定命令開啓新的線程。對addWorker方法的調用
* 會原子性地檢查runState和workerCount以防止不應該添加
* 線程錯誤報警時返回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.
* 2. 如果一個任務可以成功的進入隊列,那麼我們仍然需要再次檢查
* 是否應該添加一個線程(由於已有的線程自上次檢查後消亡了)或
* 進入方法後線程池關閉了。所以我們需要重新檢查狀態,如果停止
* 的話,回滾入隊操作。如果沒有線程可用,創建新線程
*
* 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.
* 3.如果不能把任務加入隊列,我們就嘗試創建新的線程。如果失敗,
* 我們就知道線程池關閉了或者已經飽和了,所以我們就拒絕任務。
*/
//取得當前ctl的數值
int c = ctl.get();
/**
* workerCountOf獲取ctl的低29位,也就是當前池中的線程數
* 如果當前線程數 < corePoolSize(核心線程數)
*/
if (workerCountOf(c) < corePoolSize) {
//創建新線程執行任務
if (addWorker(command, true))
return;
c = ctl.get();
}
/**
* 池中的線程數 = corePoolSize會走下面的邏輯(不會有大於的情況發生)
* 線程池未停止 && 加入隊列成功,執行以下
*/
if (isRunning(c) && workQueue.offer(command)) {
//再次檢查當前線程數
int recheck = ctl.get();
//線程池已經停止 && 刪除workQueue.offer(command)中的任務成功
if (! isRunning(recheck) && remove(command))
//拒絕任務
reject(command);
//如果線程池未停止 或者 線程池已經停止,隊列刪除任務失敗,如果線程數=0
else if (workerCountOf(recheck) == 0)
//創建新線程來執行任務
addWorker(null, false);
}
//創建新的線程失敗,拒絕該任務
else if (!addWorker(command, false))
reject(command);
}
1.10addWorker方法
/**
* Checks if a new worker can be added with respect to current
* pool state and the given bound (either core or maximum). If so,
* the worker count is adjusted accordingly, and, if possible, a
* new worker is created and started, running firstTask as its
* first task. This method returns false if the pool is stopped or
* eligible to shut down. It also returns false if the thread
* factory fails to create a thread when asked. If the thread
* creation fails, either due to the thread factory returning
* null, or due to an exception (typically OutOfMemoryError in
* Thread#start), we roll back cleanly.
*
* 檢查是否可以根據當前的池狀態和給定的界限(核心或最大值)添加新的工作者線程
* 如果可以,工作者線程會相應的做出調整,如果可能的話,一個新的工作者線程被創建
* 和運行,將firstTask作爲的一個任務。如果線程池停止或者合法關閉,此方法
* 返回false。如果線程工廠在被訪問時,沒能成功創建線程,此方法也會返回false。
* 如果因爲線程工廠返回null或者是因爲異常(典型的在Thread中的start方法拋出的
* OutOfMemoryError異常)線程創建失敗,我們都會乾淨的回滾。
*
*
* @param firstTask the task the new thread should run first (or
* null if none). Workers are created with an initial first task
* (in method execute()) to bypass queuing when there are fewer
* than corePoolSize threads (in which case we always start one),
* or when the queue is full (in which case we must bypass queue).
* Initially idle threads are usually created via
* prestartCoreThread or to replace other dying workers.
* firstTask是新的線程必須首先執行的(如果沒有的話就爲null)。工作線程在創建的時候就初始化了
* 首先要執行的任務(在execute方法中的任務),以便當線程數小於corePoolSize時(這種情況下
* 必須創建新的線程)或者是隊列已滿時(這種情況下我們必須繞過隊列)我們必須繞過隊列。最初的空閒線程
* 通常是通過prestartCoreThread或者替換其他消亡的工作線程時創建的。
*
* @param core if true use corePoolSize as bound, else
* maximumPoolSize. (A boolean indicator is used here rather than a
* value to ensure reads of fresh values after checking other pool
* state).
* 如果core爲true,使用corePoolSize作爲綁定,否則使用maximumPoolSize做綁定。(一個布爾
* 類型的指示器用在這裏,而不是在檢查其他池狀態後確保讀取新值的值)
*
* @return true if successful
*/
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()
* 至少有一個爲false的時候,返回false
* (不明白這是幹嘛的)
*/
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
//當前線程數
int wc = workerCountOf(c);
/**
* 當前線程數 > 最大線程數 或者
* 當前創建核心線程 && 當前線程數 > corePoolSize或者
* 當前創建非核心線程 && 當前線程數 > maximumPoolSize
* 返回失敗
*/
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
//CAS操作設置ctl自增1
if (compareAndIncrementWorkerCount(c))
//跳出當前循環,也就是最外層for循環
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
java.util.concurrent.ThreadPoolExecutor.Worker w = null;
try {
final ReentrantLock mainLock = this.mainLock;
//創建工作線程
w = new java.util.concurrent.ThreadPoolExecutor.Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
//加鎖
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
//持有鎖的時候重現檢查。
//退出ThreadFactory失敗,或者在獲取鎖之前關閉。
int c = ctl.get();
int rs = runStateOf(c);
//rs < SHUTDOWN只有RUNNING狀態
//當爲RUNNING狀態或者SHUTDOWN狀態,且firstTask == null
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
//新線程加入workers這個HashSet中
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;
}
1.11工作線程
/**
* Class Worker mainly maintains interrupt control state for
* threads running tasks, along with other minor bookkeeping.
* This class opportunistically extends AbstractQueuedSynchronizer
* to simplify acquiring and releasing a lock surrounding each
* task execution. This protects against interrupts that are
* intended to wake up a worker thread waiting for a task from
* instead interrupting a task being run. We implement a simple
* non-reentrant mutual exclusion lock rather than use
* ReentrantLock because we do not want worker tasks to be able to
* reacquire the lock when they invoke pool control methods like
* setCorePoolSize. Additionally, to suppress interrupts until
* the thread actually starts running tasks, we initialize lock
* state to a negative value, and clear it upon start (in
* runWorker).
*
* Worker類主要維護執行任務的線程的中斷控制狀態,以及其他一些小範圍的簿記。
* 這個類機會性的繼承了AbstractQueuedSynchronizer以便簡化圍繞每個任務執行
* 時的鎖的獲取與釋放。這可以防止中斷打算喚醒等待任務的工作線程,從而避免
* 中斷正在運行的任務。我們實現了一個簡單的非重入互斥鎖,而不是使用ReentrantLock,
* 因爲我們不希望工作任務在調用像setCorePoolSize這樣的池控制方法時能夠重新獲取鎖。
* 另外,爲了在線程實際開始運行任務之前禁止中斷,我們初始化鎖的狀態爲一個負值,並在
* 啓動線程開始執行任務時清除這個負值(在runWorker方法中)
*
*/
private final class Worker
extends AbstractQueuedSynchronizer
implements Runnable
{
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
* 這個類永遠不會被序列化,但是我們提供serialVersionUID來抑制java編譯告警
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
/** worker對象運行的線程,如果線程工廠運行失敗,可能爲空 */
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.
* 用firstTask和從線程工廠創建的線程對象創建Worker對象
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
//調用runWorker方法之前禁止中斷
/**
* 這裏添加一個新狀態-1是爲了避免當前worker線程被中斷,
* 比如調用了線程池的shutdownNow,如果當前worker狀態>=0則會設置該線程的中斷標誌。
* 這裏設置了-1所以條件不滿足就不會中斷該線程了。運行runWorker時候會調用unlock方法,
* 該方法吧status變爲了0,所以這時候調用shutdownNow會中斷worker線程。
*/
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
/** Delegates main run loop to outer runWorker */
/** 委託外部類的runWorker執行任務 */
public void run() {
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
//加鎖方法,0表示未加鎖,1表示加鎖
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) {
}
}
}
}
1.12 runWorker
/**
* Main worker run loop. Repeatedly gets tasks from queue and
* executes them, while coping with a number of issues:
*
* 1. We may start out with an initial task, in which case we
* don't need to get the first one. Otherwise, as long as pool is
* running, we get tasks from getTask. If it returns null then the
* worker exits due to changed pool state or configuration
* parameters. Other exits result from exception throws in
* external code, in which case completedAbruptly holds, which
* usually leads processWorkerExit to replace this thread.
*
* 2. Before running any task, the lock is acquired to prevent
* other pool interrupts while the task is executing, and
* clearInterruptsForTaskRun called to ensure that unless pool is
* stopping, this thread does not have its interrupt set.
*
* 3. Each task run is preceded by a call to beforeExecute, which
* might throw an exception, in which case we cause thread to die
* (breaking loop with completedAbruptly true) without processing
* the task.
*
* 4. Assuming beforeExecute completes normally, we run the task,
* gathering any of its thrown exceptions to send to
* afterExecute. We separately handle RuntimeException, Error
* (both of which the specs guarantee that we trap) and arbitrary
* Throwables. Because we cannot rethrow Throwables within
* Runnable.run, we wrap them within Errors on the way out (to the
* thread's UncaughtExceptionHandler). Any thrown exception also
* conservatively causes thread to die.
*
* 5. After task.run completes, we call afterExecute, which may
* also throw an exception, which will also cause thread to
* die. According to JLS Sec 14.20, this exception is the one that
* will be in effect even if task.run throws.
*
* The net effect of the exception mechanics is that afterExecute
* and the thread's UncaughtExceptionHandler have as accurate
* information as we can provide about any problems encountered by
* user code.
*
* @param w the worker
*/
final void runWorker(java.util.concurrent.ThreadPoolExecutor.Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
//如果當前task非空,則直接執行。否者調用getTask從任務隊列獲取一個任務執行,
// 如果任務隊列爲空,則worker退出。
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
// 如果線程池是最少是stop狀態(STOP,TIDYING,TERMINATED),則設置中斷標誌;
// 否則(RUNNININ狀態),重置中斷標誌。重置後需要重新
//檢查一下線程池狀態,因爲當重置中斷標誌時候,可能調用了線程池的shutdown方法
//改變了線程池狀態。
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;
//統計當前worker完成了多少個任務
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
//執行清理工作
processWorkerExit(w, completedAbruptly);
}
}
1.13 beforeExecute、afterExecute和processWorkerExit
/* Extension hooks */
/* 擴展的鉤子函數 */
/**
* Method invoked prior to executing the given Runnable in the
* given thread. This method is invoked by thread {@code t} that
* will execute task {@code r}, and may be used to re-initialize
* ThreadLocals, or to perform logging.
*
* 在給定線程執行給定Runnable任務之前執行的方法。此方法由將要執行任務r的線程t
* 調用,並且可能會用來重新初始化ThreadLocals或者打印一些日誌。
*
* <p>This implementation does nothing, but may be customized in
* subclasses. Note: To properly nest multiple overridings, subclasses
* should generally invoke {@code super.beforeExecute} at the end of
* this method.
* 這個方法的實現什麼都不做,但是可以在子類中定製化。注意:爲了正確的實現多層
* 重寫,子類通常該方法結束時調用super.beforeExecute
*
* @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.
*
* 此方法在執行完Runnable任務後調用。此方法是被執行任務的線程調用的。如果非空
* 那麼Throwable就是導致執行突然中斷的未捕獲的運行時異常或者錯誤。
*
* <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.
* 這個方法的實現什麼都不做,但是可以在子類中定製化。注意:爲了正確的實現多層
* 重寫,子類通常該方法結束時調用super.beforeExecute。
*
* <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:
*
* 當操作被明確的封裝在如FutureTask這樣的任務中,或者通過submit方法提交任務時,
* 這些對象會捕獲並處理計算異常,所以這些對象不會導致不會導致突然執行中斷,並且
* 內部異常不會傳遞此方法。如果你想在此方法中捕獲以上兩種異常,則可以進一步探測此類情況
* 例如在一個簡單的子類中,如果任務被終止,則打印這的異常原因或者底層異常。
*
* <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) { }
/**
* Performs cleanup and bookkeeping for a dying worker. Called
* only from worker threads. Unless completedAbruptly is set,
* assumes that workerCount has already been adjusted to account
* for exit. This method removes thread from worker set, and
* possibly terminates the pool or replaces the worker if either
* it exited due to user task exception or if fewer than
* corePoolSize workers are running or queue is non-empty but
* there are no workers.
*
* 爲消亡的線程執行清理和簿記工作。僅從工作線程調用。除非completedAbruptly
* 被設定了,否則假定workerCount已經考慮到退出而做了調整到。此方法從工作線程集合
* 中刪除線程,並且可能因爲用戶任務異常或者線程數小於corePoolSize
* 工作線程數或者阻塞隊列非空,但是沒有工作線程而可能會終止該池或替換該工作。
* @param w the worker
* @param completedAbruptly if the worker died due to user exception
*/
private void processWorkerExit(java.util.concurrent.ThreadPoolExecutor.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();
}
//嘗試設置線程池狀態爲TERMINATED,如果當前是shutdonw狀態並且工作隊列爲空
//或者當前是stop狀態當前線程池裏面沒有活動線程
tryTerminate();
int c = ctl.get();
//SHUTDOWN或RUNNING
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);
}
}
1.14 shutdown、shutdownNow
/**
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.
*
* 啓動一個有序的關閉策略,使得之前已經提交的任務全部執行完,並且不會接受新任務。
* 如果已經關閉,則調用沒有其他影響。
*
* <p>This method does not wait for previously submitted tasks to
* complete execution. Use {@link #awaitTermination awaitTermination}
* to do that.
*
* 此方法不會等待之前所有的任務都執行完,awaitTermination可以達到該效果。
*
* @throws SecurityException {@inheritDoc}
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//權限檢查
checkShutdownAccess();
//設置當前線程池狀態爲SHUTDOWN,如果已經是SHUTDOWN則直接返回
advanceRunState(SHUTDOWN);
//設置中斷標誌
interruptIdleWorkers();
//爲ScheduledThreadPoolExecutor預留的鉤子函數
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
//嘗試狀態變爲TERMINATED
tryTerminate();
}
/**
* Attempts to stop all actively executing tasks, halts the
* processing of waiting tasks, and returns a list of the tasks
* that were awaiting execution. These tasks are drained (removed)
* from the task queue upon return from this method.
*
* 嘗試停止所有執行中的任務,停止等待任務的線程,返回一個要執行的任務的list。
* 從這個方法返回後,這些任務從隊列中刪除。
*
* <p>This method does not wait for actively executing tasks to
* terminate. Use {@link #awaitTermination awaitTermination} to
* do that.
*
* 這個方法不會等待執行中的任務執行結束,用awaitTermination實現。
*
* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks. This implementation
* cancels tasks via {@link Thread#interrupt}, so any task that
* fails to respond to interrupts may never terminate.
*
* 盡最大可能的停止處理中的任務,不能保證結果。這種實現方式通過interrupt取消
* 任務,所以任何任務沒有能夠響應interrupt可能永遠都不能終止,
*
* @throws SecurityException {@inheritDoc}
*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
//權限檢查
checkShutdownAccess();
//設置線程池狀態爲stop
advanceRunState(STOP);
//中斷線程
interruptWorkers();
//移動隊列任務到tasks
tasks = drainQueue();
} finally {
mainLock.unlock();
}
//嘗試狀態變爲TERMINATED
tryTerminate();
return tasks;
}