線程池_03_源碼分析
- 關鍵變量介紹:
- 線程的狀态
- 5種
- RUNNABLE:運作狀态,接受新任務,持續處理任務隊列裡的任務
- SHUTDOWN:不再接受新任務,但要處理任務隊列裡的任務
- STOP:不接受新任務,不再處理任務隊列裡的任務,中斷正在進行中的任務
- TIDYING:表示線程池正在停止運作,中止所有任務,銷毀所有工作線程
- TERMINATED:表示線程池已停止運作,所有工作線程已被銷毀,所有任務已被清空或執行完畢
- 狀态裝換
線程池_03_源碼分析 - 細節
線程池_03_源碼分析 - 線程的狀态使用ctl表示,預設為 running
- private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
- ctl類型為AtomicInteger,那用一個基礎如何表示以上五種狀态以及線程池工作線程數量呢?int型變量占用4位元組,共32位,是以采用位表示,可以解決上述問題。5種狀态使用5種數值進行表示,需要占用3位,餘下的29位就可以用來表示線程數。是以,高三位表示程序狀态,低29位為線程數量,代碼如下:
- private staticfinal int COUNT_BITS = Integer.SIZE - 3; // 值為29
- private staticfinal int CAPACITY = (1 <<COUNT_BITS) - 1; //高三位全為0,低29位全為1,是以線程數量的表示範圍為 0 ~ 2^29
- 因為ctl分位來表示狀态和數量,下面幾個狀态僅看有效位的值
- private staticfinal int RUNNING = -1 <<COUNT_BITS; // 有效值為 111
- private staticfinal int SHUTDOWN = 0 << COUNT_BITS; // 有效值為 000
- private staticfinal int STOP = 1 << COUNT_BITS; // 有效值為 001
- private staticfinal int TIDYING = 2 << COUNT_BITS; // 有效值為 010
- private staticfinal int TERMINATED = 3 <<COUNT_BITS; // 有效值為 011
- 采用int分位表示線程池狀态和線程數量; 并且提供runStateOf(): 擷取線程池狀态 和 workerCountOf(): 擷取工作線程數量兩個方法,均為二進制操作。
- 5種
- 工作線程(Worker)
- 線程池中的工作線程以Worker作為展現,真正工作的線程為Worker的成員變量,Worker即是Runnable,又是同步器。Worker從工作隊列中取出任務來執行,并能通過Worker控制任務狀态。
- 線程的狀态
- 執行任務,源碼分析:
- 1. execute() --送出線程任務;
線程池_03_源碼分析 - 2. addWorker() -- 通過添加核心和非核心線程來執行任務
- private boolean addWorker(Runnable firstTask, boolean core) {
- int c = this.ctl.get(); // 擷取目前ctl值
- label253:
- while(!runStateAtLeast(c, 0) || !runStateAtLeast(c, 536870912) && firstTask == null && !this.workQueue.isEmpty()) {
- // workerCountOf(c)-擷取線程數 < core ? this.corePoolSize : this.maximumPoolSize 如果為true,核心線程;否則,非核心線程
- while(workerCountOf(c) < ((core ? this.corePoolSize : this.maximumPoolSize) & 536870911)) {
- // CAS操作增加線程數,跳出循環
- if (this.compareAndIncrementWorkerCount(c)) {
- boolean workerStarted = false;
- boolean workerAdded = false;
- ThreadPoolExecutor.Worker w = null;
- try {
- w = new ThreadPoolExecutor.Worker(firstTask);
- Thread t = w.thread;
- if (t != null) {
- ReentrantLock mainLock = this.mainLock;
- mainLock.lock();
-
- int c = this.ctl.get();
- if (isRunning(c) || runStateLessThan(c, 536870912) && firstTask == null) {
- if (t.isAlive()) {
- throw new IllegalThreadStateException();
- }
- this.workers.add(w);
- int s = this.workers.size();
- if (s > this.largestPoolSize) {
- this.largestPoolSize = s;
- workerAdded = true;
- if (t.isAlive()) {
- if (isRunning(c) || runStateLessThan(c, 536870912) && firstTask == null) {
- } finally {
- mainLock.unlock();
- if (workerAdded) {
- t.start();
- workerStarted = true;
- int c = this.ctl.get();
-
- if (!workerStarted) {
- this.addWorkerFailed(w);
- if (!workerStarted) {
- return workerStarted;
- c = this.ctl.get();
- // 上面的CAS操作沒成功,檢查線程池狀态與開始是否一緻;如果一緻,繼續執行此for循環,否則重新執行retry代碼塊;自旋以期CAS成功,後續才能添加線程
- if (runStateAtLeast(c, 0)) {
- continue label253;
- return false;
-
- addWorkerFailed(w)
- 首先是将Worker移除,然後通過CAS操作更新ctl,最後調用tryTerminate()操作嘗試中止線程池。
- private boolean addWorker(Runnable firstTask, boolean core) {
- 4. runWorker()
- 線程首個任務為firstTask,之後通過getTask()就從阻塞隊列裡任務。線程池提供了beforeExecute()和afterExecute()通知子類任務執行前後的回調,讓子類有時機能執行自己的事情。如果線程池已沒有任務了,工作線程達到了可退出的狀态,則将線程退出。
- 線程池執行的任務的線程,也就是Workder裡的Thread。是以在addWorker()中執行new ThreadPoolExecutor.Worker(firstTask)後;執行的是Worker.run(),run()則調用了ThreadPoolExecutor.runWorker()
線程池_03_源碼分析
- 5. getTask()
- 線程池裡的線程從阻塞隊列裡拿任務,如果存在非核心線程,假設阻塞隊列裡沒有任務,那麼非核心線程也要在等到keepAliveTime時間後才會釋放。
- 如果目前僅有核心線程存在,如果允許釋放核心線程的話,也就和非核線程的處理方式一樣,反之,則通過take()一直阻塞直到拿到任務,這也就是線程池裡的核心線程為什麼不死的原因。
線程池_03_源碼分析
- 6. processWorkerExit()
- 線上程沒有拿到任務後,退出線程
- 釋放工作線程也并沒有區分核心與非核心,也是随機進行的。所謂随機,就是在前面所說的區間範圍内,根據釋放政策,哪個線程先達到擷取不到任務的狀态,就釋放哪個線程。
線程池_03_源碼分析 - tryTerminate()
- 發現可以中止線程池時,中止,并調用terminated()進行通知。如果線程池處于RUNNABLE狀态,什麼也不做,否則嘗試中斷一個線程。中斷線程通過interruptIdleWorker()完成。
- 1. execute() --送出線程任務;