溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

怎樣解析完整的ThreadPoolExecutor

發(fā)布時(shí)間:2021-12-17 14:45:39 來源:億速云 閱讀:152 作者:柒染 欄目:大數(shù)據(jù)

怎樣解析完整的ThreadPoolExecutor,針對這個(gè)問題,這篇文章詳細(xì)介紹了相對應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡單易行的方法。

ThreadPoolExecutor源碼解析

今天為了給一個(gè)朋友做一份文檔,從源碼層級解析一下ThreadPoolExecutor。然后就直接在源碼上寫備注的形式解析。

1、常用變量的解釋

// 1. `ctl`,可以看做一個(gè)int類型的數(shù)字,高3位表示線程池狀態(tài),低29位表示worker數(shù)量
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
// 2. `COUNT_BITS`,`Integer.SIZE`為32,所以`COUNT_BITS`為29
private static final int COUNT_BITS = Integer.SIZE - 3;
// 3. `CAPACITY`,線程池允許的最大線程數(shù)。1左移29位,然后減1,即為 2^29 - 1
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
// 4. 線程池有5種狀態(tài),按大小排序如下:RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
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;

// Packing and unpacking ctl
// 5. `runStateOf()`,獲取線程池狀態(tài),通過按位與操作,低29位將全部變成0
private static int runStateOf(int c)     { return c & ~CAPACITY; }
// 6. `workerCountOf()`,獲取線程池worker數(shù)量,通過按位與操作,高3位將全部變成0
private static int workerCountOf(int c)  { return c & CAPACITY; }
// 7. `ctlOf()`,根據(jù)線程池狀態(tài)和線程池worker數(shù)量,生成ctl值
private static int ctlOf(int rs, int wc) { return rs | wc; }

/*
* Bit field accessors that don't require unpacking ctl.
* These depend on the bit layout and on workerCount being never negative.
*/
// 8. `runStateLessThan()`,線程池狀態(tài)小于xx
private static boolean runStateLessThan(int c, int s) {
   return c < s;
}
// 9. `runStateAtLeast()`,線程池狀態(tài)大于等于xx
private static boolean runStateAtLeast(int c, int s) {
   return c >= s;
}

怎樣解析完整的ThreadPoolExecutor

2、構(gòu)造方法

public ThreadPoolExecutor(int corePoolSize,
                         int maximumPoolSize,
                         long keepAliveTime,
                         TimeUnit unit,
                         BlockingQueue<Runnable> workQueue,
                         ThreadFactory threadFactory,
                         RejectedExecutionHandler handler) {
   // 基本類型參數(shù)校驗(yàn)
   if (corePoolSize < 0 ||
       maximumPoolSize <= 0 ||
       maximumPoolSize < corePoolSize ||
       keepAliveTime < 0)
       throw new IllegalArgumentException();
   // 空指針校驗(yàn)
   if (workQueue == null || threadFactory == null || handler == null)
       throw new NullPointerException();
   this.corePoolSize = corePoolSize;
   this.maximumPoolSize = maximumPoolSize;
   this.workQueue = workQueue;
   // 根據(jù)傳入?yún)?shù)`unit`和`keepAliveTime`,將存活時(shí)間轉(zhuǎn)換為納秒存到變量`keepAliveTime `中
   this.keepAliveTime = unit.toNanos(keepAliveTime);
   this.threadFactory = threadFactory;
   this.handler = handler;
}

3、提交執(zhí)行task的過程

public void execute(Runnable command) {
   if (command == null)
       throw new NullPointerException();
   /*
    * Proceed in 3 steps:
    *
    * 1. If fewer than corePoolSize threads are running, try to
    * start a new thread with the given command as its first
    * task.  The call to addWorker atomically checks runState and
    * workerCount, and so prevents false alarms that would add
    * threads when it shouldn't, by returning false.
    *
    * 2. If a task can be successfully queued, then we still need
    * to double-check whether we should have added a thread
    * (because existing ones died since last checking) or that
    * the pool shut down since entry into this method. So we
    * recheck state and if necessary roll back the enqueuing if
    * stopped, or start a new thread if there are none.
    *
    * 3. If we cannot queue task, then we try to add a new
    * thread.  If it fails, we know we are shut down or saturated
    * and so reject the task.
    */
   int c = ctl.get();
   // worker數(shù)量比核心線程數(shù)小,直接創(chuàng)建worker執(zhí)行任務(wù)
   if (workerCountOf(c) < corePoolSize) {
       if (addWorker(command, true))
           return;
       c = ctl.get();
   }
   // worker數(shù)量超過核心線程數(shù),任務(wù)直接進(jìn)入隊(duì)列
   if (isRunning(c) && workQueue.offer(command)) {
       int recheck = ctl.get();
       // 線程池狀態(tài)不是RUNNING狀態(tài),說明執(zhí)行過shutdown命令,需要對新加入的任務(wù)執(zhí)行reject()操作。
       // 這兒為什么需要recheck,是因?yàn)槿蝿?wù)入隊(duì)列前后,線程池的狀態(tài)可能會(huì)發(fā)生變化。
       if (! isRunning(recheck) && remove(command))
           reject(command);
       // 這兒為什么需要判斷0值,主要是在線程池構(gòu)造方法中,核心線程數(shù)允許為0
       else if (workerCountOf(recheck) == 0)
           addWorker(null, false);
   }
   // 如果線程池不是運(yùn)行狀態(tài),或者任務(wù)進(jìn)入隊(duì)列失敗,則嘗試創(chuàng)建worker執(zhí)行任務(wù)。
   // 這兒有3點(diǎn)需要注意:
   // 1. 線程池不是運(yùn)行狀態(tài)時(shí),addWorker內(nèi)部會(huì)判斷線程池狀態(tài)
   // 2. addWorker第2個(gè)參數(shù)表示是否創(chuàng)建核心線程
   // 3. addWorker返回false,則說明任務(wù)執(zhí)行失敗,需要執(zhí)行reject操作
   else if (!addWorker(command, false))
       reject(command);
}

4、addworker源碼解析

private boolean addWorker(Runnable firstTask, boolean core) {
   retry:
   // 外層自旋
   for (;;) {
       int c = ctl.get();
       int rs = runStateOf(c);

       // 這個(gè)條件寫得比較難懂,我對其進(jìn)行了調(diào)整,和下面的條件等價(jià)
       // (rs > SHUTDOWN) ||
       // (rs == SHUTDOWN && firstTask != null) ||
       // (rs == SHUTDOWN && workQueue.isEmpty())
       // 1. 線程池狀態(tài)大于SHUTDOWN時(shí),直接返回false
       // 2. 線程池狀態(tài)等于SHUTDOWN,且firstTask不為null,直接返回false
       // 3. 線程池狀態(tài)等于SHUTDOWN,且隊(duì)列為空,直接返回false
       // Check if queue empty only if necessary.
       if (rs >= SHUTDOWN &&
           ! (rs == SHUTDOWN &&
              firstTask == null &&
              ! workQueue.isEmpty()))
           return false;

       // 內(nèi)層自旋
       for (;;) {
           int wc = workerCountOf(c);
           // worker數(shù)量超過容量,直接返回false
           if (wc >= CAPACITY ||
               wc >= (core ? corePoolSize : maximumPoolSize))
               return false;
           // 使用CAS的方式增加worker數(shù)量。
           // 若增加成功,則直接跳出外層循環(huán)進(jìn)入到第二部分
           if (compareAndIncrementWorkerCount(c))
               break retry;
           c = ctl.get();  // Re-read ctl
           // 線程池狀態(tài)發(fā)生變化,對外層循環(huán)進(jìn)行自旋
           if (runStateOf(c) != rs)
               continue retry;
           // 其他情況,直接內(nèi)層循環(huán)進(jìn)行自旋即可
           // else CAS failed due to workerCount change; retry inner loop
       }
   }
   boolean workerStarted = false;
   boolean workerAdded = false;
   Worker w = null;
   try {
       w = new Worker(firstTask);
       final Thread t = w.thread;
       if (t != null) {
           final ReentrantLock mainLock = this.mainLock;
           // worker的添加必須是串行的,因此需要加鎖
           mainLock.lock();
           try {
               // Recheck while holding lock.
               // Back out on ThreadFactory failure or if
               // shut down before lock acquired.
               // 這兒需要重新檢查線程池狀態(tài)
               int rs = runStateOf(ctl.get());

               if (rs < SHUTDOWN ||
                   (rs == SHUTDOWN && firstTask == null)) {
                   // worker已經(jīng)調(diào)用過了start()方法,則不再創(chuàng)建worker
                   if (t.isAlive()) // precheck that t is startable
                       throw new IllegalThreadStateException();
                   // worker創(chuàng)建并添加到workers成功
                   workers.add(w);
                   // 更新`largestPoolSize`變量
                   int s = workers.size();
                   if (s > largestPoolSize)
                       largestPoolSize = s;
                   workerAdded = true;
               }
           } finally {
               mainLock.unlock();
           }
           // 啟動(dòng)worker線程
           if (workerAdded) {
               t.start();
               workerStarted = true;
           }
       }
   } finally {
       // worker線程啟動(dòng)失敗,說明線程池狀態(tài)發(fā)生了變化(關(guān)閉操作被執(zhí)行),需要進(jìn)行shutdown相關(guān)操作
       if (! workerStarted)
           addWorkerFailed(w);
   }
   return workerStarted;
}

5、線程池worker任務(wù)單元

private final class Worker
   extends AbstractQueuedSynchronizer
   implements Runnable
{
   /**
    * This class will never be serialized, but we provide a
    * serialVersionUID to suppress a javac warning.
    */
   private static final long serialVersionUID = 6138294804551838833L;

   /** Thread this worker is running in.  Null if factory fails. */
   final Thread thread;
   /** Initial task to run.  Possibly null. */
   Runnable firstTask;
   /** Per-thread task counter */
   volatile long completedTasks;

   /**
    * Creates with given first task and thread from ThreadFactory.
    * @param firstTask the first task (null if none)
    */
   Worker(Runnable firstTask) {
       setState(-1); // inhibit interrupts until runWorker
       this.firstTask = firstTask;
       // 這兒是Worker的關(guān)鍵所在,使用了線程工廠創(chuàng)建了一個(gè)線程。傳入的參數(shù)為當(dāng)前worker
       this.thread = getThreadFactory().newThread(this);
   }

   /** Delegates main run loop to outer runWorker  */
   public void run() {
       runWorker(this);
   }

   // 省略代碼...
}

6、核心線程執(zhí)行邏輯-runworker

final void runWorker(Worker w) {
   Thread wt = Thread.currentThread();
   Runnable task = w.firstTask;
   w.firstTask = null;
   // 調(diào)用unlock()是為了讓外部可以中斷
   w.unlock(); // allow interrupts
   // 這個(gè)變量用于判斷是否進(jìn)入過自旋(while循環(huán))
   boolean completedAbruptly = true;
   try {
       // 這兒是自旋
       // 1. 如果firstTask不為null,則執(zhí)行firstTask;
       // 2. 如果firstTask為null,則調(diào)用getTask()從隊(duì)列獲取任務(wù)。
       // 3. 阻塞隊(duì)列的特性就是:當(dāng)隊(duì)列為空時(shí),當(dāng)前線程會(huì)被阻塞等待
       while (task != null || (task = getTask()) != null) {
           // 這兒對worker進(jìn)行加鎖,是為了達(dá)到下面的目的
           // 1. 降低鎖范圍,提升性能
           // 2. 保證每個(gè)worker執(zhí)行的任務(wù)是串行的
           w.lock();
           // If pool is stopping, ensure thread is interrupted;
           // if not, ensure thread is not interrupted.  This
           // requires a recheck in second case to deal with
           // shutdownNow race while clearing interrupt
           // 如果線程池正在停止,則對當(dāng)前線程進(jìn)行中斷操作
           if ((runStateAtLeast(ctl.get(), STOP) ||
                (Thread.interrupted() &&
                 runStateAtLeast(ctl.get(), STOP))) &&
               !wt.isInterrupted())
               wt.interrupt();
           // 執(zhí)行任務(wù),且在執(zhí)行前后通過`beforeExecute()`和`afterExecute()`來擴(kuò)展其功能。
           // 這兩個(gè)方法在當(dāng)前類里面為空實(shí)現(xiàn)。
           try {
               beforeExecute(wt, task);
               Throwable thrown = null;
               try {
                   task.run();
               } catch (RuntimeException x) {
                   thrown = x; throw x;
               } catch (Error x) {
                   thrown = x; throw x;
               } catch (Throwable x) {
                   thrown = x; throw new Error(x);
               } finally {
                   afterExecute(task, thrown);
               }
           } finally {
               // 幫助gc
               task = null;
               // 已完成任務(wù)數(shù)加一
               w.completedTasks++;
               w.unlock();
           }
       }
       completedAbruptly = false;
   } finally {
       // 自旋操作被退出,說明線程池正在結(jié)束
       processWorkerExit(w, completedAbruptly);
   }
}

關(guān)于怎樣解析完整的ThreadPoolExecutor問題的解答就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI