線程池源碼剖析
1. 手寫一個簡單線程池
目前業界線程池的設計,普遍採用的都是生產者——消費者模型,線程的使用方是生產者,而線程池就是一個消費者;
下面來設計一個簡易的線程池MythreadPool,它的設計原理跟我們的ThreadPoolExecutor的設計思想是一致的;
class MythreadPool {
//用阻塞隊列來保存任務
BlockingQueue<Runnable> workQueue;
List<WorkThread> workers = new ArrayList<>();
public MythreadPool(int poolSize, BlockingQueue<Runnable> blockingQueue) {
this.workQueue = blockingQueue;
for(int i=0; i<poolSize; i++) {
WorkThread workThread = new WorkThread();
workThread.start();
workers.add(workThread);
}
}
//提交任務
public void excute(Runnable runnable) {
workQueue.add(runnable);
}
class WorkThread extends Thread {
@Override
public void run() {
//這裏是個死循環,所以工作的線程不會結束,會在這裏一直等待從阻塞隊列中獲取任務;
while (true) {
try {
Runnable task = workQueue.take();
task.run();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public class Test2 {
public static void main(String[] args) {
MythreadPool mythreadPool = new MythreadPool(3, new ArrayBlockingQueue<>(3));
mythreadPool.excute(new Runnable() {
@Override
public void run() {
System.out.println("hello my threadPool!!!!");
}
});
}
}
輸出:
hello my threadPool!!!
由於沒有實現關閉線程池的方法,上述輸出是不會結束的,需強制關閉;
2. 線程池體系架構
Executor是位於juc包下的一個接口;
可以看到頂層是Executor接口,這個接口就一個方法:
-
void execute(Runnable command);
接下來是ExecutorService接口,這個接口作用是:
- 提供了線程池生命週期的一些管理方法;
- 接下來是AbstractExecutorService,這個抽象類則是具體實現了上面ExecutorService接口中的那些方法;
最下面的就是我們常用的ThreadPoolExecutor,下面具體進行講解;
2. ThreadPoolExcutor源碼解讀
1. 工作狀態概述
ThradPoolExecutor提供了對線程生命週期的控制,規定線程池有如下五種狀態:
- RUNNING(運行)
- 能夠接受新的任務,也可以處理阻塞隊列裏面的任務;
- SHUTDOWN(待關閉)
- 不能夠接受新的任務,繼續處理阻塞隊列裏的任務;
- STOP(停止)
- 不能夠接受新的任務,也不會處理阻塞隊列裏的任務,並且會中斷正在處理的任務;
- TIDYING(整理)
- 所有的任務已經停止,ctl記錄的工作線程數爲0,線程池會變爲TIDYING狀態,此狀態線程池會執行鉤子方法terminated();
- TERMINATED(終止)
- 完全終止,且已經釋放了所有的資源;
根據源碼註釋,使用ctl的高三位來表示上面五種狀態,低29位來表示線程池中的工作線程數;
所謂的工作線程數,就是已經被允許start並且不允許被停止的線程;
//ctl是一個原子數,線程安全的(CAS),初始值的設定代表RUNNING狀態和工作線程數爲0;
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
//COUNT_BITS即爲32-3,爲29;
private static final int COUNT_BITS = Integer.SIZE - 3;
//表示工作線程的最大數,2^29 - 1;
//即:00011111 11111111 11111111 11111111
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;
//獲取線程池狀態
//c 來與上CAPACITY取反,即與上:11100000 00000000 00000000 0000000,即取得c的前三位;
private static int runStateOf(int c) { return c & ~CAPACITY; }
//獲取工作線程數
//c 來與上CAPACITY,即與上:00011111 11111111 11111111 11111111,即獲得c的第27位;
private static int workerCountOf(int c) { return c & CAPACITY; }
//將狀態與線程數進行或運算,剛好就組成了ctl; 因爲rs的低27位全爲零,wc的高3位全爲0,而0與任意數
//進行或運算的結果就是那個任意數;
private static int ctlOf(int rs, int wc) { return rs | wc; }
2. 工作狀態的轉換
- (1):RUNNING 轉換爲 SHUTDOWN :在調用shutdown()方法時;
- (2):RUNNING或SHUTDOWN 轉換爲 STOP:調用shutdownNow()方法時;
- (3):SHUTDOWN 轉化爲 TIDYING:當阻塞隊列和工作線程數都爲0時;
- (4):STOP 轉化爲 TIDYING:當工作線程數爲0時;
- (5):TIDYING 轉化爲 TERMINATED:當terminated()鉤子方法完成時;