1. 程式人生 > >併發程式設計——ThreadPoolExecutor原始碼分析(一)

併發程式設計——ThreadPoolExecutor原始碼分析(一)

前言

執行緒池是併發程式設計中最重要的應用之一,使用執行緒池可以防止大量的建立和銷燬執行緒的過程,可以節省很多的記憶體空間,提高程式的響應率和cpu的利用率,並且也可以對執行緒進行統一管理和監控。這裡將分幾篇文章介紹一下執行緒池的原始碼分析。本篇是分析ThreadPoolExecutor中的ctl變數

ctl變數

原始碼中的解釋

ThreadPoolExecutor中有個欄位是ctl,具體來說是對執行緒池的執行狀態和池子中的有效執行緒數量的控制的一個欄位變數,我們可以看看原始碼中的解釋:

/**
 * 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
 *
 * 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.

可以看到ctl是AtomicInteger物件,裡面的操作都是基於CAS的原子操作。一個ctl變數包含兩部分資訊,因為int型別的變數是32位的,所以高3位表示執行緒池的執行狀態(runState),低29位表示執行緒池中有效執行緒數(workerCount)。

所以,當我們知道了執行緒池中的執行狀態和有效執行緒數,就可以通過ctlOf方法計算出ctl的值:

private static int ctlOf(int rs, int wc) { return rs | wc; }

反過來,我們也可以通過ctl計算出runState和workerCount的值:

private static int
runStateOf(int c) { return c & ~CAPACITY; } private static int workerCountOf(int c) { return c & CAPACITY; }

其中CAPACITY是(2^29)-1, 也就是高三位是0,低29位是1的一個int型別的數字常量。這個CAPACITY表示執行緒池中有效執行緒的上限值。這個值的計算過程:

private static final int COUNT_BITS = Integer.SIZE - 3; // 29
private static final int CAPACITY   =
(1 << COUNT_BITS) - 1;

執行緒池的狀態

執行緒池中有五種狀態:

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;
private static final int SHUTDOWN   =  0 << COUNT_BITS;
private static final int STOP       =  1 << COUNT_BITS;
private static final int TIDYING    =  2 << COUNT_BITS;
private static final int TERMINATED =  3 << COUNT_BITS;

其中COUNT_BITS的值是29,在後邊的原始碼分析過程中,我們其實只需要知道這幾個狀態是逐漸遞增的即可。比如說在原始碼中看到 rs < SHUTDOWN 其實就是表示此時執行緒池的執行狀態是RUNNING。

五種狀態的解釋:

(1)RUNNING:執行狀態,能接受提交新的任務,並且也能處理阻塞佇列中的任務。

(2)SHUTDOWN:關閉狀態,不再接受新提交的任務,但是可以處理阻塞在任務佇列中已儲存的任務。線上程池處於RUNNING狀態的時候,呼叫shutdown方法執行緒池即變為此狀態。

(3)STOP:停止狀態,不再接受新提交的任務,也不會處理阻塞佇列中已儲存的任務,並且會中斷正在處理的任務,線上程池處於RUNNING狀態或者SHUTDOWN狀態的時候,呼叫shutdownNow方法執行緒池即進入該狀態。

(4)TIDYING:清理狀態,所有的任務都已經終止,workerCount有效執行緒數量為0,執行緒池進入該狀態後呼叫terminated方法可以使執行緒池進入Terminated狀態。當執行緒池處於SHUTDOWN狀態時,如果此後執行緒池中沒有執行緒並且阻塞佇列中沒有要執行的任務,就會進入到這個狀態;當執行緒池處於STOP狀態時,如果此時執行緒池中沒有執行緒了,執行緒池會進入該狀態。
(5)TERMINATED:terminated()方法執行之後會進入該狀態。

其他欄位引數

//執行緒池控制器
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//任務佇列
private final BlockingQueue<Runnable> workQueue;
//全域性鎖
private final ReentrantLock mainLock = new ReentrantLock();
//工作執行緒集合
private final HashSet<Worker> workers = new HashSet<Worker>();
//終止條件 - 用於等待任務完成後才終止執行緒池
private final Condition termination = mainLock.newCondition();
//曾建立過的最大執行緒數
private int largestPoolSize;
//執行緒池已完成總任務數
private long completedTaskCount;
//工作執行緒建立工廠
private volatile ThreadFactory threadFactory;
//飽和拒絕策略執行器
private volatile RejectedExecutionHandler handler;
//工作執行緒活動保持時間(超時後會被回收) - 納秒
private volatile long keepAliveTime;
/**
 * 允許核心工作執行緒響應超時回收
 * false:核心工作執行緒即使空閒超時依舊存活
 * true:核心工作執行緒一旦超過keepAliveTime仍然空閒就被回收
 */
private volatile boolean allowCoreThreadTimeOut;
//核心工作執行緒數
private volatile int corePoolSize;
//最大工作執行緒數
private volatile int maximumPoolSize;
//預設飽和策略執行器 - AbortPolicy -> 直接丟擲異常
private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();

下一章

下一章將會去寫一下ThreadPoolExecutor的建構函式和核心引數。