怎樣解析完整的ThreadPoolExecutor

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

創(chuàng)新互聯(lián)堅持“要么做到,要么別承諾”的工作理念,服務領(lǐng)域包括:做網(wǎng)站、成都網(wǎng)站設計、企業(yè)官網(wǎng)、英文網(wǎng)站、手機端網(wǎng)站、網(wǎng)站推廣等服務,滿足客戶于互聯(lián)網(wǎng)時代的全州網(wǎng)站設計、移動媒體設計的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡建設合作伙伴!

ThreadPoolExecutor源碼解析

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

1、常用變量的解釋

// 1. `ctl`,可以看做一個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;
}

2、構(gòu)造方法

public ThreadPoolExecutor(int corePoolSize,
                         int maximumPoolSize,
                         long keepAliveTime,
                         TimeUnit unit,
                         BlockingQueue<Runnable> workQueue,
                         ThreadFactory threadFactory,
                         RejectedExecutionHandler handler) {
   // 基本類型參數(shù)校驗
   if (corePoolSize < 0 ||
       maximumPoolSize <= 0 ||
       maximumPoolSize < corePoolSize ||
       keepAliveTime < 0)
       throw new IllegalArgumentException();
   // 空指針校驗
   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`,將存活時間轉(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í)行任務
   if (workerCountOf(c) < corePoolSize) {
       if (addWorker(command, true))
           return;
       c = ctl.get();
   }
   // worker數(shù)量超過核心線程數(shù),任務直接進入隊列
   if (isRunning(c) && workQueue.offer(command)) {
       int recheck = ctl.get();
       // 線程池狀態(tài)不是RUNNING狀態(tài),說明執(zhí)行過shutdown命令,需要對新加入的任務執(zhí)行reject()操作。
       // 這兒為什么需要recheck,是因為任務入隊列前后,線程池的狀態(tài)可能會發(fā)生變化。
       if (! isRunning(recheck) && remove(command))
           reject(command);
       // 這兒為什么需要判斷0值,主要是在線程池構(gòu)造方法中,核心線程數(shù)允許為0
       else if (workerCountOf(recheck) == 0)
           addWorker(null, false);
   }
   // 如果線程池不是運行狀態(tài),或者任務進入隊列失敗,則嘗試創(chuàng)建worker執(zhí)行任務。
   // 這兒有3點需要注意:
   // 1. 線程池不是運行狀態(tài)時,addWorker內(nèi)部會判斷線程池狀態(tài)
   // 2. addWorker第2個參數(shù)表示是否創(chuàng)建核心線程
   // 3. addWorker返回false,則說明任務執(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);

       // 這個條件寫得比較難懂,我對其進行了調(diào)整,和下面的條件等價
       // (rs > SHUTDOWN) ||
       // (rs == SHUTDOWN && firstTask != null) ||
       // (rs == SHUTDOWN && workQueue.isEmpty())
       // 1. 線程池狀態(tài)大于SHUTDOWN時,直接返回false
       // 2. 線程池狀態(tài)等于SHUTDOWN,且firstTask不為null,直接返回false
       // 3. 線程池狀態(tài)等于SHUTDOWN,且隊列為空,直接返回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)進入到第二部分
           if (compareAndIncrementWorkerCount(c))
               break retry;
           c = ctl.get();  // Re-read ctl
           // 線程池狀態(tài)發(fā)生變化,對外層循環(huán)進行自旋
           if (runStateOf(c) != rs)
               continue retry;
           // 其他情況,直接內(nèi)層循環(huá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();
           }
           // 啟動worker線程
           if (workerAdded) {
               t.start();
               workerStarted = true;
           }
       }
   } finally {
       // worker線程啟動失敗,說明線程池狀態(tài)發(fā)生了變化(關(guān)閉操作被執(zhí)行),需要進行shutdown相關(guān)操作
       if (! workerStarted)
           addWorkerFailed(w);
   }
   return workerStarted;
}

5、線程池worker任務單元

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)建了一個線程。傳入的參數(shù)為當前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
   // 這個變量用于判斷是否進入過自旋(while循環(huán))
   boolean completedAbruptly = true;
   try {
       // 這兒是自旋
       // 1. 如果firstTask不為null,則執(zhí)行firstTask;
       // 2. 如果firstTask為null,則調(diào)用getTask()從隊列獲取任務。
       // 3. 阻塞隊列的特性就是:當隊列為空時,當前線程會被阻塞等待
       while (task != null || (task = getTask()) != null) {
           // 這兒對worker進行加鎖,是為了達到下面的目的
           // 1. 降低鎖范圍,提升性能
           // 2. 保證每個worker執(zhí)行的任務是串行的
           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
           // 如果線程池正在停止,則對當前線程進行中斷操作
           if ((runStateAtLeast(ctl.get(), STOP) ||
                (Thread.interrupted() &&
                 runStateAtLeast(ctl.get(), STOP))) &&
               !wt.isInterrupted())
               wt.interrupt();
           // 執(zhí)行任務,且在執(zhí)行前后通過`beforeExecute()`和`afterExecute()`來擴展其功能。
           // 這兩個方法在當前類里面為空實現(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;
               // 已完成任務數(shù)加一
               w.completedTasks++;
               w.unlock();
           }
       }
       completedAbruptly = false;
   } finally {
       // 自旋操作被退出,說明線程池正在結(jié)束
       processWorkerExit(w, completedAbruptly);
   }
}

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

網(wǎng)頁題目:怎樣解析完整的ThreadPoolExecutor
網(wǎng)站地址:http://bm7419.com/article20/ijphco.html

成都網(wǎng)站建設公司_創(chuàng)新互聯(lián),為您提供品牌網(wǎng)站建設、電子商務、品牌網(wǎng)站制作、標簽優(yōu)化、網(wǎng)站建設、網(wǎng)站排名

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)頁設計公司