- 關鍵變量介紹:
- 線程的狀態
- 5種
- RUNNABLE:運行狀態,接受新任務,持續處理任務隊列裏的任務
- SHUTDOWN:不再接受新任務,但要處理任務隊列裏的任務
- STOP:不接受新任務,不再處理任務隊列裏的任務,中斷正在進行中的任務
- TIDYING:表示線程池正在停止運作,中止所有任務,銷燬所有工作線程
- TERMINATED:表示線程池已停止運作,所有工作線程已被銷燬,所有任務已被清空或執行完畢
- 狀態裝換
- 細節
- 線程的狀態使用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() --提交線程任務;
- 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();
- try {
- 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();
- }
- } finally {
- 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;
- }
- 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()
- 5. getTask()
- 線程池裏的線程從阻塞隊列裏拿任務,如果存在非核心線程,假設阻塞隊列裏沒有任務,那麼非核心線程也要在等到keepAliveTime時間後纔會釋放。
- 如果當前僅有核心線程存在,如果允許釋放核心線程的話,也就和非核線程的處理方式一樣,反之,則通過take()一直阻塞直到拿到任務,這也就是線程池裏的核心線程爲什麼不死的原因。
- 6. processWorkerExit()
- 在線程沒有拿到任務後,退出線程
- 釋放工作線程也並沒有區分核心與非核心,也是隨機進行的。所謂隨機,就是在前面所說的區間範圍內,根據釋放策略,哪個線程先達到獲取不到任務的狀態,就釋放哪個線程。
- tryTerminate()
- 發現可以中止線程池時,中止,並調用terminated()進行通知。如果線程池處於RUNNABLE狀態,什麼也不做,否則嘗試中斷一個線程。中斷線程通過interruptIdleWorker()完成。
線程池_03_源碼分析
線程池_03_源碼分析
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.