ThreadPoolExecutor源碼閱讀

1.任務拒絕策略:RejectedExecutionHandler

線程池提供了四種繼承RejectedExecutionHandler的拒絕策略,我們可以分別來看一下:

1.默認拒絕策略:AbortPolicy

   /**
     * A handler for rejected tasks that throws a
     * {@code RejectedExecutionException}.
     */
    public static class AbortPolicy implements RejectedExecutionHandler {
        public AbortPolicy() { }
        //可以看到這邊的拒絕的方式是拋出異常
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException("Task " + r.toString() +
                " rejected from " +
                e.toString());
        }
    }

2.不拋錯拒絕策略:DiscardPolicy

        這個拒絕策略,不會執行報錯,是silent版的AbortPolicy策略

    /**
     * A handler for rejected tasks that silently discards the
     * rejected task.
     */
    public static class DiscardPolicy implements RejectedExecutionHandler {

        public DiscardPolicy() { }

        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
        }
    }

3.移除隊頭元素:DiscardOldestPolicy

        這個拒絕策略會把阻塞隊列中等待的最後一個任務移出,然後把新任務添加進去(可能失敗可能成功)

	/**
     * A handler for rejected tasks that discards the oldest unhandled
     * request and then retries {@code execute}, unless the executor
     * is shut down, in which case the task is discarded.
     */
    public static class DiscardOldestPolicy implements RejectedExecutionHandler {
        public DiscardOldestPolicy() { }

		//先把隊頭的元素移出,然後嘗試入隊
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                e.getQueue().poll();
                e.execute(r);
            }
        }
    }

4.通過主線程直接執行:CallerRunsPolicy

    /**
     * A handler for rejected tasks that runs the rejected task
     * directly in the calling thread of the {@code execute} method,
     * unless the executor has been shut down, in which case the task
     * is discarded.
     */
    public static class CallerRunsPolicy implements RejectedExecutionHandler {
        public CallerRunsPolicy() { }
		
		//線程池未關閉,直接執行沒有入隊的線程
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            if (!e.isShutdown()) {
                r.run();
            }
        }
    }

5.設置任務拒絕策略

        這邊可以根據業務需求自定義任務拒絕策略。

    public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
        if (handler == null)
            throw new NullPointerException();
        this.handler = handler;
    }

2.線程池狀態說明

        這邊保存了五個線程池的狀態,瞭解線程池狀態才能更好理解線程池

    // runState is stored in the high-order bits
    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;
狀態 解釋
RUNNING 運行態,可處理新任務並執行隊列中的任務
SHUTDOW 關閉態,不接受新任務,但處理隊列中的任務
STOP 停止態,不接受新任務,不處理隊列中任務,且打斷運行中任務
TIDYING 整理態,所有任務已經結束,workerCount = 0 ,將執行terminated()方法
TERMINATED 結束態,terminated() 方法已完成

3.BlokingQueue:隊列策略

1.LinkedBlockingQueue

        參考:LinkedBlockingQueue源碼閱讀

2.SynchronousQueue

        參考:SynchronousQueue源碼閱讀

4.ThreadPoolExecutor實現

1.execute

        execute本身有一個處理過程,流程如下:
        1.當線程池的工作集數量小於corepoolsize的時候,嘗試添加到工作集,如果成功,直接返回
        2.如果添加失敗(可能是這個過程中其他線程也併發添加,導致數量大於corepoosize了),這個時候需要重新獲取一下工作集的數量
        3.判斷線程池是RUNNING狀態,如果是,添加任務到阻塞隊列,添加成功之後還要去判斷一下線程池是否是RUNNIING狀態(可能在這段時間內被shutdown了)
        4.如果是RUNNIONG狀態,線程池工作集爲0,添加一個空的工作集是爲了讓他處理阻塞隊列中的任務,如果不是RUNNING狀態通過拒絕策略拒絕進來的任務.
        5.如果第一次判斷線程池狀態不是RUNNING(步驟3),嘗試添加到工作集,這個時候大小就是maximumPoolSize了,如果添加成功相安無事,如果添加失敗通過拒絕策略處理

public void execute(Runnable command) {
        //如果線程爲空,報錯
        if (command == null) {
            throw new NullPointerException();
        }
        //拿到RUNNING的線程數量
        int c = ctl.get();
        //有效線程數小於【核心池線程數】
        if (workerCountOf(c) < corePoolSize) {
            //添加任務成功返回
            if (addWorker(command, true)) {
                return;
            }
            //如果添加到工作線程隊列失敗,需要拿到RUNNING的線程數量繼續往下走
            //失敗的原因可能是   1.線程池在添加到工作集的過程中被SHUTDOWN了    2.線程池數量超過corePoolSize,因爲併發高導致
            c = ctl.get();
        }

        //前提:有效線程數> corePoolSize ,線程池是running狀態,提交到等待隊列(成功)
        if (isRunning(c) && workQueue.offer(command)) {
            //再次獲取一下運行狀態
            int recheck = ctl.get();
            //如果不是RUNNING狀態,嘗試從等待隊列中移除成功
            //(SynchronousQueue因爲是沒有容量的,所以remove永遠返回false)、LinkedBlockingQueue除非節點爲空或者找不到對應節點纔會返回false
            if (!isRunning(recheck) && remove(command)) {
                reject(command);
            }
            //這邊是不滿足上面的if的條件就是:isRunning(recheck) || !remove(command)纔會進入,判斷worker數量是否爲0
            //如果是running的狀態,回創建一個空的worker去執行,如果不是running的狀態隊列爲空會返回false,不會創建worker
            else if (workerCountOf(recheck) == 0) {
                addWorker(null, false);
            }
        }
        //如果線程池不是running狀態且進入阻塞隊列失敗,嘗試開啓maximumPoolSize(這邊的第二個參數false),添加到工作集
        //如果失敗就啓動拒絕策略
        else if (!addWorker(command, false)) {
            reject(command);
        }
    }

1.execute流程圖

在這裏插入圖片描述

2.addWorker

        addWoker主要分成三個部分:
        1.根據線程池狀態和工作集數量判斷是否添加任務
        2.添加任務創建新的worker的激活
        3.異常要把worker移除工作集的處理

 private boolean addWorker(Runnable firstTask, boolean core) {
        retry:
        for (; ; ) {
            //拿到RUNNING的線程數量
            int c = ctl.get();
            //獲取線程池運行狀態
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            //如果是shutdown之後的狀態,不是shutdown直接返回false,不支持新增
            //否則是shutdown,但是傳進來的Runnable爲空並且隊列不爲空,要繼續往下執行.說明還有任務沒結束
            //--- 這個地方失敗可能是線程池被SHUTDOWN了

            //變式 : rs >= SHUTDOWN && (rs != SHUTDOWN || firstTask != null || workQueue.isEmpty())
            //變式2: rs >= SHUTDOWN && rs != SHUTDOWN || rs >= SHUTDOWN  && firstTask != null || rs >= SHUTDOWN && workQueue.isEmpty())
            //變式3: rs > SHUTDOWN || rs == SHUTDOWN  && firstTask != null || rs == SHUTDOWN && workQueue.isEmpty())
            //所以可以這樣表述:如果線程池是 SHUTDOWN以上的狀態(直接返回false不允許添加了)   如果線程池是SHUTDOWN狀態,當添加的RUNNABLE不爲空或者工作隊列爲空了不允許添加
            //說明 當線程池SHUTDOWN了,不能添加不爲null的任務,當阻塞隊列爲空了,也不能繼續添加,直接返回false
            //其他情況可以往下
            if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty())) {
                return false;
            }


            for (; ; ) {
                //獲取運行中的worker數量
                int wc = workerCountOf(c);
                //如果達到上限,這邊的core決定是用corePoolSize 還是 maximumPoolSize來判斷大小
                // -- 這個地方失敗的有可能是因爲高併發導致線程數量超過限制
                if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) {
                    return false;
                }
                //沒有達到上限往這邊走,cas操作使工作線程數量加1,跳出循環
                if (compareAndIncrementWorkerCount(c)) {
                    break retry;
                }
                // Re-read ctl
                //上述的CAS嘗試失敗,說明數量被修改了,所以這邊要重新獲取一次
                c = ctl.get();
                //如果線程池運行狀態和之前獲取的不一致,返回到retry,重新進入for循環往後面走
                if (runStateOf(c) != rs) {
                    continue retry;
                }
                // else CAS failed due to workerCount change; retry inner loop
            }
        }
        //新線程啓動標識
        boolean workerStarted = false;
        //新線程添加到workers標識
        boolean workerAdded = false;
        Worker w = null;
        try {
            //創建一個新的Worker,因爲worker也是一個Runnable,在構造函數中,會把worker賦值給線程工廠,生成一個Thread(Runnable = this.worker)的線程,所以下面的start相當於啓動這個worker.
            w = new Worker(firstTask);
            final Thread t = w.thread;
            //Runnable不爲空
            if (t != null) {
                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狀態或者SHUTDOWN狀態並且任務爲null.
                    if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
                        // precheck that t is startable
                        //判斷線程是否啓動過了,啓動過了則報錯,因爲需要交給 工作集來處理
                        if (t.isAlive()) {
                            throw new IllegalThreadStateException();
                        }
                        //添加到工作集
                        workers.add(w);
                        //判斷修改最大線程池的大小
                        int s = workers.size();
                        if (s > largestPoolSize) {
                            largestPoolSize = s;
                        }
                        //添加成功設置爲true
                        workerAdded = true;
                    }
                } finally {
                    //最終解鎖
                    mainLock.unlock();
                }
                //如果worker添加成功
                if (workerAdded) {
                    //worker對應的線程進行啓動
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            //這個參數是false只有一種情況就是當Runnable==null的時候
            if (!workerStarted) {
                addWorkerFailed(w);
            }
        }
        return workerStarted;
    }

1.是否添加任務
        先來看第一部分,是否添加任務,上面的代碼有兩個for循環去處理,我們可以看到除了兩處return false和一處break retry,其他的地方都是一直在嘗試,所以我們其實可以這麼理解,有兩種情況是嘗試添加失敗了,有一種情況是添加成功,繼續往下執行worker的處理

        那麼看一下第一處的失敗 ,上面我們把這個表達式分解得到的結果是:
        如果線程池是 SHUTDOWN以上的狀態(直接返回false不允許添加了) 如果線程池是SHUTDOWN狀態,當添加的RUNNABLE不爲空或者工作隊列爲空了不允許添加

        第二次的失敗比較簡單,超過線程池的corepoolsize或者maximumpoolsize大小的時候不能添加
        成功往下走的情況是當cas添加worker集數量+1,成功的時候跳出循環。

2.添加新的worker
        這邊的話,會先去創建一個新的worker,Thread是從線程工廠中獲取,傳入的Runnable實現是worker本身,因爲worker就是一個Runnable的實現類,所以可以直接扔到Thread裏面去創建
        這邊同樣會重新去判斷一下線程池的狀態,只有在RUNNING的時候能添加非空的任務,在SHUTDOWN的時候可以添加空任務。
        當隊列添加成功的時候,纔會去啓動對應的線程,如果添加失敗,在finally的時候會處理添加worker失敗的時間。這裏的失敗可能來自於兩個地方:
        1.線程本來就是激活的,拋出錯誤
        2.不滿足Running或者是shutdown狀態但是添加的是空任務
        只有這兩種情況,才視爲失敗,會在finally的時候處理添加失敗的操作.

        Worker(Runnable firstTask) {
            // inhibit interrupts until runWorker
            //-1表示該worker還沒有運行
            setState(-1);
            //設置線程任務
            this.firstTask = firstTask;
            //設置線程
            this.thread = getThreadFactory().newThread(this);
        }

3.處理添加worker失敗
        處理worker失敗,這邊會把他移出工作集,並且嘗試終止線程池tryTerminate,只是嘗試,因爲出錯的地方有兩個,有可能是線程池狀態被改變了,所以需要去嘗試是否可以終止,加速終止過程

    private void addWorkerFailed(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //移除worker
            if (w != null) {
                workers.remove(w);
            }
            //減少數量
            decrementWorkerCount();
            //嘗試終止線程池
            tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }

4.嘗試終止線程池
        這邊有幾種情況是不需要終止的(第一個return):
        1.線程池還是running狀態
        2.線程池已經被終止掉了,狀態變成TIDYING或者TERMINATED
        3.線程池狀態是SHUTDOWN,但是阻塞隊列不爲空,等待任務執行結束再進行終止.
        如果不滿足上面的條件則繼續往下:
        此時是shutdown狀態,如果工作集的數量不爲0,會調用interruptIdleWorkers方法,這個方法我們下面會講到,這個方法傳true,會嘗試去中斷一個等待任務的worker線程。
        繼續往下,如果是SHUTDOWN狀態,並且阻塞隊列已經清空了,先要設置線程池狀態,這邊提供了一個terminated模板給子類實現。

  final void tryTerminate() {
        for (; ; ) {
            //拿到RUNNING的線程數量
            int c = ctl.get();
            //1.線程還在運行 2.atleast狀態是TIDYING或者TERMINATED,已經終止了 3.SHUTDOWN但是隊列不爲空,等待隊列結束   返回
            if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && !workQueue.isEmpty())) {
                return;
            }

            // Eligible to terminate
            //SHUTDOWN狀態,如果此時線程池還有線程、中斷喚醒一個正在等任務的空閒worker 返回
            if (workerCountOf(c) != 0) {
                interruptIdleWorkers(ONLY_ONE);
                return;
            }

            //如果狀態是SHUTDOWN,workQueue也爲空了
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                //將線程池的ctl變成TIDYING(所有的任務被終止,workCount爲0,爲此狀態時將會調用terminated()方法),期間ctl有變化就會失敗,會再次for循環
                if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                    try {
                        //提供模板方法給子類實現
                        terminated();
                    } finally {
                        //設置狀態爲TERMINATED
                        ctl.set(ctlOf(TERMINATED, 0));
                        //喚醒調用了 等待線程池終止的線程 awaitTermination()
                        termination.signalAll();
                    }
                    return;
                }
            } finally {
                //最終解鎖
                mainLock.unlock();
            }
            // else retry on failed CAS
        }
    }

3.addWorker流程圖

在這裏插入圖片描述

4.線程執行Worker.run

        worker的run是直接調用runWorker方法的,這邊也可以分成幾個步驟去理解
        1.任務的獲取,這邊說的任務的獲取包括兩個方面,一個是worker本身的Runnable不爲空,優先執行自己,否則要去阻塞隊列裏面去去獲取,注意這邊不是if的判斷,而是一個while循環,也就是說如果Worker的Runnable執行完了,會再去隊列中拿任務,直到隊列裏面也沒有任務了.
        2.任務執行
        3.worker執行結束的處理

final void runWorker(Worker w) {
        //拿到當前執行線程
        Thread wt = Thread.currentThread();
        //拿到任務,Runnable
        Runnable task = w.firstTask;
        w.firstTask = null;
        // allow interrupts
        //new Worker()是state==-1,此處是調用Worker類的tryRelease()方法,將state置爲0, 而interruptIfStarted()中只有state>=0才允許調用中斷
        w.unlock();
        boolean completedAbruptly = true;
        try {
            //任務不爲空 或者 從阻塞隊列中getTask()不爲null
            while (task != null || (task = getTask()) != null) {
                // 鎖定
                w.lock();
               //線程池狀態大於等於STOP、或者【任務線程】有中斷標識 並且當前worker線程沒有中斷 ,需要對當前的worker線程進行中斷
                //後面可以看到shutdownNow會對所有的任務進行中斷狀態的設置,這邊的處理就是對應的shutdownNow的處理
                if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) && !wt.isInterrupted()) {
                    wt.interrupt();
                }
                try {
                    //模板方法
                    beforeExecute(wt, task);
                    Throwable thrown = null;
                    try {
                        //運行Runnable
                        task.run();
                    } catch ( )
                    {      ...........//省略
                    }
                    } finally {
                        //模板方法
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    //worker的完成任務數量加一,此時是線程安全的 ,釋放鎖
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            //每個工作線程進行處理最後都有一個處理退出的操作,主要是做一些資源的重建和計數的操作
            processWorkerExit(w, completedAbruptly);
        }
    }

1.從隊列中獲取任務
        這邊也是一個死循環,可以看到,有兩個地方return null說明阻塞隊列不返回任務了,有一個地方是返回了非空的任務,還有一個地方進行了continue操作。我們分別來看一下:
        第一個return null,是當線程池狀態大於等於STOP,或者是線程池狀態等於SHUTDOWN,但是阻塞隊列裏面沒有任務了。這邊其實可以這樣理解,如果是調用shutdownNow方法,會使得線程狀態一下子變成STOP,那麼這邊阻塞隊列裏面的任務就不能再參與運行了,因爲後面會返回隊列中沒有處理的這部分任務。如果是shutdown的情況,會修改爲shutdown狀態,阻塞隊列中的任務依然會繼續消耗掉。所以這邊的判斷條件設置成這樣.
        第二個return null;當滿足了上述條件:
        1.工作集數量大於maximumPoolSize
        2.獲取超時並且阻塞隊列爲空
        通過CAS去減少工作集數量,如果成功直接返回null,如果失敗繼續循環

        return非空任務的情況先從阻塞隊列中獲取任務,如果任務爲空則設置超時,進行下一輪的循環,否則直接返回任務.

private Runnable getTask() {
        boolean timedOut = false; // Did the last poll() time out?

        for (; ; ) {
            //線程運行狀態 和 RUNNING數量
            int c = ctl.get();
            int rs = runStateOf(c);

            // Check if queue empty only if necessary.
            // 線程池狀態爲shutdown,且workQueue爲空
            // 線程池狀態大於stop(shutdownNow()會導致變成STOP)
            //workcount-1,返回null
            //變式: rs >= SHUTDOWN && workQueue.isEmpty() || rs >= STOP
            if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
                decrementWorkerCount();
                return null;
            }

            //獲取一下工作集數量
            int wc = workerCountOf(c);

            // Are workers subject to culling?
            //設置超時時間爲true   或者  工作集數量 > corePoolSize
            boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;

            //工作集數量超過 maximumPoolSize 或者 (上一次獲取超時 )並且 (工作集大於1 或者 等待隊列爲空)
            //這邊雖然表達式比較複雜,但是可以理解爲:超時返回null、大於maximumPoolSize返回null,等待隊列爲空返回null
            if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
                //嘗試將線程數減一併返回null
                if (compareAndDecrementWorkerCount(c)) {
                    return null;
                }
                //嘗試失敗,繼續循環
                continue;
            }

            try {
                //計時則在規定時間出隊列,非計時通過take獲取。
                Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
                //不爲空,返回Runnable,是從等待隊列中返回的
                if (r != null) {
                    return r;
                }
                //如果失敗設置超時
                timedOut = true;
            } catch (InterruptedException retry) {
                //被中斷的話,設置非超時,被中斷的
                timedOut = false;
            }
        }
    }

2.執行任務
        這邊在執行任務之前有一個步驟是:線程池狀態大於等於STOP、或者【任務線程】有中斷標識 並且當前worker線程沒有中斷 ,需要對當前的worker線程進行中斷。後面可以看到shutdownNow會對所有的任務進行中斷狀態的設置,這邊的處理就是對應的shutdownNow的處理
在任務執行前後提供了兩個模板方法。

worker退出的處理
        worker的退出這邊有一個入參:completedAbruptly,如果while循環進去了,處理過最少一次任務,這個入參就是false,如果while循環沒有進去的話,這個入參就是true,可以把它理解爲是否突然退出
        如果是突然退出的話,worker數量需要進行-1操作,突然退出說明沒有任務了或者是第一次處理任務的時候就出現異常了,所以保底起見先把工作集數量-1,如果是false,就不要執行這一步操作
        再往下,這個worker退出,則需要移出工作集,真殘忍.
        調用tryTerminate方法,包含兩種情況,可能是線程池shutdown了,也可能是短期內確實沒有任務了,參考上面描述的該方法。

        再往下判斷如果是RUNNING或者SHUTDOWN狀態。如果不是突然退出,下面有一步操作,因爲可能包含兩種狀態
        如果是RUNNING的時候,工作集的數量是會增加的,這邊判斷的是否需要去處理阻塞隊列中的任務(工作集中的線程數量滿足處理的數量要求,這只是一次worker的退出,所以如果添加也只會添加一個),如果不需要直接返回。如果需要往下添加一個空任務的worker。
        如果是SHUTDOWN的狀態,一樣的道理,如果阻塞隊列沒有任務,不需要添加空任務的worker,等待運行中的worker結束就可以了,如果阻塞隊列不爲空,並且線程池真正運行的數量不夠,則需要添加一個,來加快SHUTDOWN的進程。

 private void processWorkerExit(Worker w, boolean completedAbruptly) {
        // If abrupt, then workerCount wasn't adjusted
        //completedAbruptly爲true時代表發生了異常,線程數減一
        if (completedAbruptly) {
            decrementWorkerCount();
        }

        //鎖住,從工作集中移除
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            //統計完成任務數
            completedTaskCount += w.completedTasks;
            workers.remove(w);
        } finally {
            mainLock.unlock();
        }

        //根據當前線程狀態判斷是否需要結束線程池,嘗試
        tryTerminate();

        int c = ctl.get();
        //如果是RUNNING 和SHUTDOWN狀態
        if (runStateLessThan(c, STOP)) {
            //正常沒發生異常
            if (!completedAbruptly) {
                int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
                if (min == 0 && !workQueue.isEmpty()) {
                    min = 1;
                }
                //不需要添加線程的工作集的情況
                if (workerCountOf(c) >= min) {
                    //   not needed
                    return;
                }
            }
            addWorker(null, false);
        }
    }

5.Worker.run流程圖

在這裏插入圖片描述

2.shutdown

        shutdown方法不會影響正在執行的線程,他會等待正在執行的線程執行結束,然後終止,這邊的執行步驟分別爲:
        1.判斷是否有權限進行shutdown操作
        2.死循環設置線程池的狀態爲shutdown
        3.對還在【等待執行】的worker List 設置中斷標識(不打擾在執行中的線程)
        4.ScheduledThreadPoolExecutor的鉤子,這邊沒有用到
        5.嘗試終止線程池:worker集清理工作等,加快終止

    public void shutdown() {
        final ReentrantLock mainLock = this.mainLock;
        //鎖定
        mainLock.lock();
        try {
            //判斷是否有權限終止
            checkShutdownAccess();
            //死循環設置爲SHUTDOWN狀態
            advanceRunState(SHUTDOWN);
            //對還在【等待執行】的worker List 設置中斷標識(不打擾在執行中的線程),在AQS的處理中 如果有中斷標識會自己中斷
            interruptIdleWorkers();
            //ScheduledThreadPoolExecutor的鉤子?後面看了再說吧
            onShutdown(); // hook for ScheduledThreadPoolExecutor
        } finally {
            //解鎖
            mainLock.unlock();
        }
        //嘗試終止線程池
        tryTerminate();
    }

        我們來看一下他怎麼做到不打擾正在運行中的worker的
        因爲worker本身繼承了AQS,所以具備state,如果不是運行中的,state等於0.可以嘗試設置成功,tryLock成功的前提是worker還沒進入執行,還在等待.

    private void interruptIdleWorkers() {
        interruptIdleWorkers(false);
    }
 private void interruptIdleWorkers(boolean onlyOne) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers) {
                Thread t = w.thread;
                //不是中斷狀態並且獲取鎖成功(這個worker可能正在等待執行),因爲worker本身繼承了AQS,所以具備state,如果不是運行中的,state等於0.可以嘗試設置成功
                if (!t.isInterrupted() && w.tryLock()) {
                    try {
                        //設置中斷狀態
                        t.interrupt();
                    } catch (SecurityException ignore) {
                    } finally {
                        w.unlock();
                    }
                }
                if (onlyOne){
                    break;
                }
            }
        } finally {
            mainLock.unlock();
        }
    }

3.shutdownNow

        shutdownNow比較過分,直接設置線程池狀態爲Stop,即空任務的worker(用於處理阻塞隊列的任務)都不能添加。
        同樣他也需要檢查權限
        設置Stop狀態
        對執行中的線程進行設置中斷
        因爲shutdownNow不支持對阻塞隊列中的任務進行處理了,所以直接彈出阻塞隊列的任務,然後返回這些任務

public List<Runnable> shutdownNow() {
        List<Runnable> tasks;
        final ReentrantLock mainLock = this.mainLock;
        //鎖定
        mainLock.lock();
        try {
            //校驗SHUTDOWN權限
            checkShutdownAccess();
            //強行設置爲STOP狀態直到成功
            advanceRunState(STOP);
            //對正在執行的worker設置中斷標識
            interruptWorkers();
            //彈出阻塞隊列
            tasks = drainQueue();
        } finally {
            mainLock.unlock();
        }
        //嘗試終止
        tryTerminate();
        //返回阻塞隊列中的任務
        return tasks;
    }

        對執行中的線程設置中斷標識:

    private void interruptWorkers() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            for (Worker w : workers){
                //對正在執行的任務設置 中斷狀態
                w.interruptIfStarted();
            }
        } finally {
            mainLock.unlock();
        }
    }

        void interruptIfStarted() {
            Thread t;
            if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
                try {
                    t.interrupt();
                } catch (SecurityException ignore) {
                }
            }
        }

        彈出阻塞隊列中的任務,並且這些在等待的任務需要返回,因爲還沒執行

private List<Runnable> drainQueue() {
        BlockingQueue<Runnable> q = workQueue;
        ArrayList<Runnable> taskList = new ArrayList<Runnable>();
        q.drainTo(taskList);
        if (!q.isEmpty()) {
            for (Runnable r : q.toArray(new Runnable[0])) {
                if (q.remove(r))
                    taskList.add(r);
            }
        }
        return taskList;
    }
發佈了84 篇原創文章 · 獲贊 15 · 訪問量 3192
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章