Java 并發(fā)編程系列 --- 線程池(ThreadPoolExecutor)源碼解析

在開始解析線程池之前,先簡(jiǎn)單的總結(jié)一下創(chuàng)建線程的幾種方式:

  • 繼承Thread類
  • 實(shí)現(xiàn)Runnable接口
  • 使用Future和Callable
  • 借助線程池

上面是創(chuàng)建一個(gè)線程的四種方式适秩,在實(shí)際的開發(fā)中是推薦使用線程池來實(shí)現(xiàn)多線程的并發(fā)操作绊序。ThreadPoolExecutor是線程池的核心實(shí)現(xiàn)類,用來執(zhí)行被提交的任務(wù)秽荞。

在開始分析之前骤公,先看一下線程池的主要處理流程,如下圖:

image.png

上圖是線程池的處理流程扬跋,先從宏觀上阶捆,看一下處理流程,下面結(jié)合代碼看看具體是如何實(shí)現(xiàn)的钦听,那么開始分析:

數(shù)據(jù)結(jié)構(gòu)

繼承關(guān)系
public class ThreadPoolExecutor extends AbstractExecutorService

類的定義非常的簡(jiǎn)單洒试,只是繼承了一個(gè)抽象類 AbstractExecutorService 。并沒有很好的反映出它的一個(gè)繼承關(guān)系朴上, 不要著急垒棋,看一下下面的這張圖:

ThreadPoolExecutor繼承關(guān)系.png

通過上圖可以發(fā)現(xiàn),Executor才是站在金子塔頂端的那個(gè)痪宰, 由它來掌控全局叼架, 當(dāng)然Executor這個(gè)接口也是非常的高冷畔裕, 只定義了一個(gè) void execute(Runnable command) 方法,將任務(wù)的提交與任務(wù)的執(zhí)行進(jìn)行了分離乖订。ExecutorService接口繼承了Executor 接口扮饶,添加了一些帶返回的submit()方法和關(guān)閉方法shutdown()等。 AbstractExecutorService抽象類實(shí)現(xiàn)了ExecutorService()提供了一些方法的默認(rèn)實(shí)現(xiàn)乍构,ThreadPoolExector繼承了抽象類甜无,并實(shí)現(xiàn)了Executor接口的execute()方法。

基本屬性
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));

ctl是ThreadPoolThread類中很重要的一個(gè)字段蜡吧,它是一個(gè)特殊的int類型變量。 并且是一個(gè)原子操作占键,能保證線程的安全性昔善。 ctl這個(gè)變量包含了兩部分的信息 , 簡(jiǎn)寫表示 c:

  • workerCount:線程池內(nèi)有效線程的數(shù)量 : 簡(jiǎn)寫表示 wc
  • runState:線程池的運(yùn)行狀態(tài) ,running ,shutdown 等 ,簡(jiǎn)寫表示為 rs

它是怎么做到一個(gè)變量包含兩個(gè)信息的,詳細(xì)分析一下:

一個(gè)int類型的變量用二進(jìn)制表示是32 位的畔乙,其中高3為表示的是線程池的狀態(tài)君仆,低29位表示的線程中有效線程的數(shù)量。 這設(shè)計(jì)厲害了牲距,還可以這么玩返咱。

runState是一個(gè)生命周期的控制狀態(tài),值如下:

  • RUNNING : 接受新任務(wù)并處理隊(duì)列任務(wù) 牍鞠, 數(shù)值表示 -1 << 29
  • SHUTDOWN :不接受新任務(wù)并處理隊(duì)列任務(wù) ,數(shù)值表示 0 << 29
  • STOP : 不接受新任務(wù)咖摹,不處理隊(duì)列任務(wù),并且會(huì)中斷正在處理的線程任務(wù),數(shù)值表示 1 << 29
  • TIDYING : 所有任務(wù)終止难述,workCount為0萤晴,清理狀態(tài) 數(shù)值表示 2 << 29
  • TERMINATED :terminated()方法執(zhí)行后執(zhí)行該狀態(tài) ,數(shù)值表示 3 << 29

上面的5個(gè)常量,按照從小到大的順序依次性進(jìn)行排列胁后。線程池的運(yùn)行狀態(tài)要小于線程池的其它狀態(tài)店读。

上面說了ctl中包含了兩部分信息,下面的代碼是它們的具體實(shí)現(xiàn):
先看將兩部分合并的方法:

//將runState和workerCount 合并到一個(gè)ctl中
//RUNNING的值為 -1 << 29  , wc 為 0 
//rs的二進(jìn)制表示為:     11100000000000000000000000000000
//wc二進(jìn)制表示為:        00000000000000000000000000000000
//                     --------------------------------  | 運(yùn)算
//所以兩者 | 運(yùn)算后:值為 11100000000000000000000000000000 
//rs填充ctl的高三位攀芯, wc填充ctl的低29 位  屯断,初始化wc的值為零
private static int ctlOf(int rs, int wc) { return rs | wc; }

再看將ctl分解為runState和workCount方法

//該方法用于取出runState的值

//00011111111111111111111111111111  CAPACITY的二進(jìn)制表示

//11100000000000000000000000000000  ~ 按位取反操作,如果是1111 取反就是 0000
//11100000000000000000000000000000  c的二進(jìn)制表示
//--------------------------------  運(yùn)算
//11100000000000000000000000000000  返回結(jié)果
private static int runStateOf(int c)     { return c & ~CAPACITY; }

//該方法用于取出workCount的值
//11100000000000000000000000000000
//00011111111111111111111111111111
//--------------------------------
//00000000000000000000000000000000   返回結(jié)果
private static int workerCountOf(int c)  { return c & CAPACITY; }

上面演示了在初始化線程池的時(shí)候侣诺,c , rs , wc 是如何運(yùn)算的殖演。如果沒有明白,請(qǐng)去看一下位移運(yùn)算年鸳。

構(gòu)造方法

ThreadPoolExecutor提供了四個(gè)構(gòu)造方法剃氧,會(huì)涉及到幾個(gè)非常重要的參數(shù),構(gòu)造方法看下面的這一個(gè)就可以了阻星,因?yàn)槠渌娜齻€(gè)構(gòu)造方法朋鞍,都是使用的this調(diào)用的下面這個(gè)方法已添。ThreadPoolExecutor的構(gòu)造方法除了進(jìn)行參數(shù)的合法性和賦值賦值操作外,并沒有其他多余的動(dòng)作滥酥。

//corePoolSize : 核心線程池的實(shí)現(xiàn)大小
//maximumPoolSize : 最大線程池的實(shí)現(xiàn)大小
//keepAliveTime :線程活動(dòng)保持時(shí)間更舞,線程空閑超過這個(gè)時(shí)間就會(huì)終止
//unit : 線程活動(dòng)保持時(shí)間的單位
//workQueue :用來暫時(shí)保存任務(wù)的工作隊(duì)列
//threadFactory:用于設(shè)置創(chuàng)建線程的工廠,可以通過線程工廠給每個(gè)線程設(shè)置有意義的名字
//handler : 當(dāng)ThreadPoolExecutor已經(jīng)關(guān)閉或已經(jīng)飽和時(shí)坎吻,execute()方法將調(diào)用Handler
public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler) {
        //判斷參數(shù)合法性缆蝉,不合法拋出IllegalArgumentException異常
        if (corePoolSize < 0 ||
            maximumPoolSize <= 0 ||
            maximumPoolSize < corePoolSize ||
            keepAliveTime < 0)
            throw new IllegalArgumentException();
        //隊(duì)列,線程工廠瘦真,handler為空拋出空指針異常
        if (workQueue == null || threadFactory == null || handler == null)
            throw new NullPointerException();
        //賦值操作
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.workQueue = workQueue;
        this.keepAliveTime = unit.toNanos(keepAliveTime);
        this.threadFactory = threadFactory;
        this.handler = handler;
    }

上面只是簡(jiǎn)單的介紹了一下參數(shù)的含義刊头,下面具體說明一下:

  • corePoolSize:當(dāng)提交一個(gè)任務(wù)時(shí),線程池會(huì)創(chuàng)建一個(gè)線程來執(zhí)行任務(wù)诸尽,即使有空閑線程也會(huì)創(chuàng)建一個(gè)新的原杂,等到需要執(zhí)行的任務(wù)數(shù)大于線程池基本大小時(shí)就不再創(chuàng)建。如果調(diào)用了prestartAllCoreThreads()方法您机,線程池會(huì)提前創(chuàng)建并啟動(dòng)所有基本的線程穿肄。

  • workQueue:用于保存等待執(zhí)行任務(wù)的阻塞隊(duì)列

    • ArrayBlockingQueue:基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列
    • LinkedBlockingQueue:基于鏈表結(jié)構(gòu)的阻塞隊(duì)列,按照FIFO排序元素
    • SynchronousQueue:一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列
    • PriorityBlockingQueue:一個(gè)具有優(yōu)先級(jí)的無限阻塞隊(duì)列
  • maximumPoolSize:線程池允許創(chuàng)建的最大線程數(shù)际看,如果隊(duì)列滿了咸产,并且已經(jīng)創(chuàng)建的線程數(shù)小于最大線程數(shù),則線程池會(huì)創(chuàng)建新的線程去執(zhí)行任務(wù)仲闽。

  • ThreadFactory:創(chuàng)建線程的工廠

  • RejectedExecutionHandler:當(dāng)隊(duì)列和線程池都滿了脑溢,說明線程池已經(jīng)處于飽和狀態(tài),那么必須采取一種策略來處理新提交的任務(wù)

    • AbortPolicy:直接拋出異常
    • CallerRunsPolicy:只用調(diào)用者所在的線程來運(yùn)行任務(wù)
    • DiscardOldestPloicy:丟棄隊(duì)列里最近的一個(gè)任務(wù)赖欣,并執(zhí)行當(dāng)前任務(wù)
    • DiscardPolicy:不處理焚志,丟棄掉
向線程池提交任務(wù)

提交任務(wù)有兩個(gè)方法,一個(gè)是execute()一個(gè)是submit()方法畏鼓,前一個(gè)不會(huì)返回值酱酬,后一個(gè)會(huì)返回值。submit()方法不再本次解析的范圍內(nèi)云矫,感興趣的可以自行研究簡(jiǎn)單提一下膳沽,submit()方法在AbstractExecutorService抽象類中實(shí)現(xiàn) ,借助 FutureTask進(jìn)行封裝让禀,在execute() 中執(zhí)行挑社。

execute()方法
對(duì)于線程池,作為使用方的我們只能向線程池提交任務(wù)巡揍,而對(duì)于任務(wù)是否執(zhí)行和什么時(shí)候執(zhí)行痛阻,并不能控制。

 public void execute(Runnable command) {
     //驗(yàn)證參數(shù)合法性
     if (command == null)
         throw new NullPointerException();
   
     //獲取ctl的值
     int c = ctl.get();

     //如果當(dāng)前線程池中線程的數(shù)量小于核心線程的數(shù)量
     if (workerCountOf(c) < corePoolSize) {
            //執(zhí)行addWorker方法腮敌,
            //addWorker 將任務(wù)添加到隊(duì)列阱当,并啟動(dòng)俏扩,成功返回true,失敗返回false
            if (addWorker(command, true))
                //addWorker返回true, 添加成功弊添,結(jié)束execute()方法運(yùn)行
                return;
            c = ctl.get();
     }
     
     //線程池的運(yùn)行狀態(tài)已經(jīng)不是RUNNING
     //線程池的狀態(tài)是RUNNING录淡,wc > corePoolSize,隊(duì)列未滿
     if (isRunning(c) && workQueue.offer(command)) {
         int recheck = ctl.get();
         // 非RUNNING狀態(tài) 則從workQueue中移除任務(wù)并拒絕
         if (! isRunning(recheck) && remove(command))
              reject(command);
         // 線程池處于RUNNING狀態(tài) || 線程池處于非RUNNING狀態(tài)但是任務(wù)移除失敗
         else if (workerCountOf(recheck) == 0)
             // 這行代碼是為了SHUTDOWN狀態(tài)下沒有活動(dòng)線程了油坝,但是隊(duì)列里還有任務(wù)沒執(zhí)行這種特殊情況嫉戚。
            // 添加一個(gè)null任務(wù)是因?yàn)镾HUTDOWN狀態(tài)下,線程池不再接受新任務(wù)
            //但要運(yùn)行任務(wù)隊(duì)列中的任務(wù)
              addWorker(null, false);
      }
       
      //線程池非RUNNING狀態(tài)
      //隊(duì)列滿了澈圈,啟動(dòng)新的線程也失敗了彬檀,采用拒絕策略
      else if (!addWorker(command, false))
         reject(command);
}

上面的注釋已經(jīng)詳細(xì)的標(biāo)注了if中判斷的條件,這里在簡(jiǎn)單的總結(jié)一下瞬女,execute()方法的添加策略窍帝,分為幾種情形:

  • wc < corePoolSize , 創(chuàng)建一個(gè)新的線程,并提交任務(wù)
  • wc = corePoolSize , 任務(wù)隊(duì)列未滿拆魏,則添加到阻塞隊(duì)列
  • corePoolSize < wc < maximumPoolSize ,阻塞隊(duì)列已滿盯桦,嘗試創(chuàng)建一個(gè)新的進(jìn)程來執(zhí)行任務(wù)
  • wc >= maximunPoolSize ,阻塞隊(duì)列已滿慈俯,則采用拒絕隊(duì)列渤刃。

如果阻塞隊(duì)列是無界隊(duì)列,則 maximunPoolSize 這個(gè)參數(shù)就沒有什么效果贴膘。

上面的四種情形也和文章開始的流程圖相契合卖子,可以在回頭看一下。

addworker() 也在線程池的調(diào)度邏輯中扮演了很重要的角色刑峡,下面來看一下洋闽,它具體都進(jìn)行了哪些操作。

添加任務(wù)的方法邏輯可能有一點(diǎn)繞突梦, 多看幾遍就可以了诫舅。

private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (;;) {
            //獲取ctl的值
            int c = ctl.get();
            //計(jì)算rs的值,用于判斷線程池當(dāng)前的狀態(tài)
            int rs = runStateOf(c);

            //下面的if判斷兩種情況
            //1.rs >= SHUTDOWN  ==> 線程池處于非運(yùn)行狀態(tài)
            //2.線程池狀態(tài)為SHUTDOWN宫患,此時(shí)不再接收新的任務(wù)刊懈,但還要處理隊(duì)列中的任務(wù)
            //  firstTask !=null 不再接收新任務(wù), 隊(duì)列為空,任務(wù)已經(jīng)處理完成娃闲。都直接返回虚汛。 
            if (rs >= SHUTDOWN && ! (rs == SHUTDOWN &&firstTask == null && ! workQueue.isEmpty()))
                return false;
            //執(zhí)行到此處,說明線程處在RUNNING狀態(tài)
            //或者 SHUTDOWN狀態(tài)皇帮,隊(duì)列中還有任務(wù)要執(zhí)行
            for (;;) {
                //計(jì)算線程池中有效線程的數(shù)量
                int wc = workerCountOf(c);
                //判斷wc的數(shù)量是否符合規(guī)則
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                //cas ,+1 操作 卷哩,成功返回true,失敗返回false
                if (compareAndIncrementWorkerCount(c))
                    break retry;  //退出循環(huán)
                c = ctl.get();  // Re-read ctl
                //+1 操作失敗, 從新檢測(cè)線程池的狀態(tài)属拾,繼續(xù)循環(huán)
                if (runStateOf(c) != rs)
                    continue retry; 
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
        //workCount +1 操作成功将谊,執(zhí)行下面的步驟

        boolean workerStarted = false;
        boolean workerAdded = false;
        Worker w = null;
        try {
            //Worker: 實(shí)現(xiàn)了Runnable的私有內(nèi)部類冷溶,將任務(wù)進(jìn)行封裝
            w = new Worker(firstTask);
            final Thread t = w.thread;  //w.thread 由Work構(gòu)造方法初始化
            if (t != null) {
                //獲取全局鎖,并發(fā)訪問workers ,加鎖處理
                final ReentrantLock mainLock = this.mainLock;
                mainLock.lock();
                try {
                    // Recheck while holding lock.
                    // Back out on ThreadFactory failure or if
                    // shut down before lock acquired.
                    int rs = runStateOf(ctl.get());
                    //RUNNING狀態(tài)瓢娜,SHUTDOWN狀態(tài)清理隊(duì)列中的任務(wù)
                    if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                        if (t.isAlive()) // precheck that t is startable
                            throw new IllegalThreadStateException();
                        //將work添加到HashSet集合中挂洛。
                        workers.add(w);
                        int s = workers.size();
                        if (s > largestPoolSize)
                            largestPoolSize = s;
                        workerAdded = true;
                    }
                } finally {
                    mainLock.unlock();
                }
                if (workerAdded) {
                    //啟動(dòng)線程執(zhí)行任務(wù)
                    t.start(); //執(zhí)行的是ThreadPoolExecuteor的runWorker方法
                    workerStarted = true;
                }
            }
        } finally {
            //線程啟動(dòng)失敗
            if (! workerStarted)
                //刪除添加的任務(wù)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

上面的注釋已經(jīng)很清楚,可能還有人覺得有些混亂眠砾,那么在串一下這個(gè)處理流程:

線程池的狀態(tài)在不斷的發(fā)生變化虏劲,添加新的任務(wù)時(shí),先判斷一下當(dāng)前的線程狀態(tài)褒颈。
在調(diào)用addWorker()之前柒巫,判斷了此時(shí)的wc數(shù)量是小于< corePoolSize的。那么也就說只要線程池狀態(tài)是RUNNING, 就可以直接創(chuàng)建新的線程來執(zhí)行提交的任務(wù)谷丸。但是還是要排除堡掏,線程池是非RUNNING的這種情況。if (rs >= SHUTDOWN && ! (rs == SHUTDOWN &&firstTask == null && !workQueue.isEmpty()))便有了這個(gè)判斷條件刨疼。 所以如果addWorker()方法沒有創(chuàng)建新線程也沒有提交新任務(wù)泉唁,直接返回false的話,只能是下列情形中的一種:

  • 線程池是STOP|TIDYING|TERMINATED 中的一種狀態(tài)
  • 線程池是SHUNDOWN狀態(tài)揩慕,但 firstTask != null
  • 線程池是SHUNDOWN狀態(tài)亭畜,但 workQueue 是空
  • 線程的有效線程數(shù)量大于CAPACITY|| 大于(corePoolSize或者maximumPoolSize)

上面的 大于(corePoolSize或者maximumPoolSize)取決于隊(duì)列是否已滿

t.start()是調(diào)用的runWorker方法,因?yàn)閃orker的run()方法迎卤,調(diào)用的是ThreadPoolExecutor類中的RunWorker()方法拴鸵,看一下RunWorker的具體實(shí)現(xiàn)。
runWorker()

final void runWorker(Worker w) {
    //獲取當(dāng)前運(yùn)行的線程
    Thread wt = Thread.currentThread();
    //獲取Worker中包裝的Runnable
    Runnable task = w.firstTask;
    w.firstTask = null;
    //允許中斷蜗搔,因?yàn)樵趙ork的構(gòu)造方法中抑制了中斷
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
         //task 就是 w.firstTask ,也就是包裝后的任務(wù)
         //task 不是null 則進(jìn)入while循環(huán)中
         //如果 task == null , 則從隊(duì)列中取出一個(gè)任務(wù)執(zhí)行
         //如果隊(duì)列為空劲藐,則task還是null ,不進(jìn)入while循環(huán)。
         while (task != null || (task = getTask()) != null) {
            //加鎖
            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())
                    //滿足上面的條件樟凄,則執(zhí)行中斷操作
                    wt.interrupt();
                try {
                    //任務(wù)提交之前是否需要一些操作聘芜,交由子類實(shí)現(xiàn)
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        task.run();  //執(zhí)行任務(wù),執(zhí)行Runnable中的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 {
                        //交給子類的實(shí)現(xiàn)方法
                        afterExecute(task, thrown);
                    }
                } finally {
                    //修改task值缝龄,獲取新的任務(wù)執(zhí)行
                    task = null;
                    //完成任務(wù)數(shù)+1
                    w.completedTasks++;
                    //釋放鎖
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            //清理線程的后續(xù)
            processWorkerExit(w, completedAbruptly);
    }
}

看一下上面方法的核心代碼汰现,while循環(huán)。如果傳入的對(duì)象不為null將直接運(yùn)行傳入的任務(wù)二拐,傳入任務(wù)完成之后服鹅,task變?yōu)閚ull, 則調(diào)用getTask()方法來獲取隊(duì)列中的任務(wù),如果隊(duì)列中一直有任務(wù)存在這又是一個(gè)死循環(huán)百新,while會(huì)一直循環(huán)下去企软,當(dāng)然這只是一種極端的情況,在getTask()方法有返回null的條件饭望,當(dāng)getTask()方法返回null,則退出runWorker()方法仗哨。

getTask()

private Runnable getTask() {
        //線程等待超時(shí)變量形庭,默認(rèn)為false
        boolean timedOut = false; // Did the last poll() time out?
        //死循環(huán)
        for (;;) {
            //獲取ctl的值
            int c = ctl.get();
            //獲取線程池當(dāng)前的狀態(tài)值
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //判斷線程池當(dāng)前所處的狀態(tài)
            //線程的狀態(tài)不是RUNNING,隊(duì)列為空。
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                //工作線程的數(shù)量-1 
                decrementWorkerCount();
                return null;
            }
            //工作線程的數(shù)量
            int wc = workerCountOf(c);

            // Are workers subject to culling?
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            if ((wc > maximumPoolSize || (timed && timedOut))
                && (wc > 1 || workQueue.isEmpty())) {
                if (compareAndDecrementWorkerCount(c))
                    return null;
                continue;
            }

            try {
                //沒有超時(shí)厌漂,獲取一個(gè)任務(wù)
                Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
                if (r != null)
                    return r;
                timedOut = true;
            } catch (InterruptedException retry) {
                timedOut = false;
            }
        }
    }

上面的getTask()方法內(nèi)部是一個(gè)死循環(huán)萨醒,結(jié)束死循環(huán)的話可以通過break或者return關(guān)鍵字。上面方法使用了return null 來結(jié)束任務(wù)獲取苇倡,分為以下情形富纸。

  • 線程池狀態(tài) >= SHUTDOWN && (rs >= STOP 任務(wù)隊(duì)列為空)
  • 線程獲取任務(wù)等待超時(shí)或者任務(wù)隊(duì)列為空了
  • 成功取到了不為null的任務(wù)
關(guān)閉線程池
public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            checkShutdownAccess();
            //線程池狀態(tài)設(shè)置為SHUTDOWN
            advanceRunState(SHUTDOWN);
            //中斷所有空閑線程,等待隊(duì)列任務(wù)執(zhí)行完成
            interruptIdleWorkers();
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            mainLock.unlock();
        }
        tryTerminate();
    }

可以通過調(diào)用線程池的shutdown或者shutdownNow方法來關(guān)閉線程池旨椒,它們的原理是遍歷池中的工作線程晓褪,然后逐個(gè)調(diào)用線程的interrupt方法來中斷線程,所以無法響應(yīng)中斷的任務(wù)可能永遠(yuǎn)無法終止综慎。shutdownNow首先將線程池的狀態(tài)設(shè)置為STOP,然后嘗試停止所有正在執(zhí)行的或者暫停的任務(wù)并返回等待執(zhí)行的任務(wù)列表涣仿。而shutdown只是將線程池的狀態(tài)設(shè)置成SHUTDOWN,然后中斷所有沒有在執(zhí)行的任務(wù)線程。

參考:
書籍:《JAVA并發(fā)編程藝術(shù) - 方騰飛》
博客: http://blog.csdn.net/clevergump/article/details/50688008

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末示惊,一起剝皮案震驚了整個(gè)濱河市好港,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌米罚,老刑警劉巖钧汹,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異阔拳,居然都是意外死亡崭孤,警方通過查閱死者的電腦和手機(jī)类嗤,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門糊肠,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人遗锣,你說我怎么就攤上這事货裹。” “怎么了精偿?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵弧圆,是天一觀的道長。 經(jīng)常有香客問我笔咽,道長搔预,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任叶组,我火速辦了婚禮拯田,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘甩十。我一直安慰自己船庇,他們只是感情好吭产,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著鸭轮,像睡著了一般臣淤。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上窃爷,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天邑蒋,我揣著相機(jī)與錄音,去河邊找鬼按厘。 笑死寺董,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的刻剥。 我是一名探鬼主播遮咖,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼造虏!你這毒婦竟也來了御吞?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬榮一對(duì)情侶失蹤漓藕,失蹤者是張志新(化名)和其女友劉穎陶珠,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體享钞,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡揍诽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了栗竖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片暑脆。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖狐肢,靈堂內(nèi)的尸體忽然破棺而出添吗,到底是詐尸還是另有隱情,我是刑警寧澤份名,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布碟联,位于F島的核電站,受9級(jí)特大地震影響僵腺,放射性物質(zhì)發(fā)生泄漏鲤孵。R本人自食惡果不足惜贾富,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一忱叭、第九天 我趴在偏房一處隱蔽的房頂上張望译断。 院中可真熱鬧碴开,春花似錦德谅、人聲如沸婚瓜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至漆际,卻和暖如春淆珊,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背奸汇。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來泰國打工施符, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人擂找。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓戳吝,卻偏偏與公主長得像,于是被迫代替她去往敵國和親贯涎。 傳聞我的和親對(duì)象是個(gè)殘疾皇子听哭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容