線程池_03_源碼分析

線程池_03_源碼分析 - 幕布
線程池_03_源碼分析
  • 關鍵變量介紹:
    •  線程的狀態
      • 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(): 獲取工作線程數量兩個方法,均爲二進制操作。
    • 工作線程(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;
                    • }
                  • } finally {
                    • mainLock.unlock();
                  • }
                  • if (workerAdded) {
                    • t.start();
                    • workerStarted = true;
                  • }
                • }
              • } finally {
                • if (!workerStarted) {
                  • this.addWorkerFailed(w);
                • }
              • }
              • 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()操作嘗試中止線程池。
    • 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()完成。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章