ThreadPoolExecutor的應用和實現分析(下)—— 生命週期相關原始碼分析

n8765發表於2015-04-24

前面提到ExecutorService是對Executor的擴充套件,增加了submit()等提交和呼叫任務的方法,也增加了對Executor生命週期的定義。本篇將結合shutdown()、shutdownNow()、awaitTermination()和tryTerminate()幾個方法的實現對ThreadPoolExecutor生命週期相關的邏輯做分析整理。

0. ExecutorService的生命週期方法和ThreadPoolExecutor的生命週期實現

ExecutorService中,和生命週期相關的,宣告瞭5個方法:

  • awaitTermination() 阻塞等待shutdown請求後所有執行緒終止,會有時間引數,超時和中斷也會令方法呼叫結束
  • isShutdown()  通過ctl屬性判斷當前的狀態是否不是RUNNING狀態
  • isTerminated()  通過ctl屬性判斷當前的狀態是否為TERMINATED狀態
  • shutdown() 關閉Executor,不再接受提交任務
  • shutdownNow() 關閉Executor,不再接受提交任務,並且不再執行入佇列中的任務

前面的文章也已經介紹過,在ThreadPoolExecutor的實現中,定義了五個生命週期狀態,標識了整個執行緒池物件所處的狀態階段,用來實現生命週期相關的方法。

1. ThreadPoolExecutor的shutdown()

我們先來看看shutdown()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(SHUTDOWN);
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}

其實邏輯比較簡單,嘗試將狀態切換到SHUTDOWN,這樣就不會再接收新的任務提交。對空閒執行緒進行中斷呼叫。最後檢查執行緒池執行緒是否為0,並嘗試切換到TERMINATED狀態。

2. ThreadPoolExecutor的shutdownNow()

再來看看shutdownNow()方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public List shutdownNow() {
    List tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

主要所做的事情就是切換ThreadPoolExecutor到STOP狀態,中斷所有worker,並將任務佇列中的任務取出來,不再執行。最後嘗試修改狀態到TERMINATED。

3. shutdown()和shutdownNow()的區別

shutdown()新的任務不會再被提交到執行緒池,但之前的都會依舊執行,通過中斷方式停止空閒的(根據沒有獲取鎖來確定)執行緒。

shutdownNow()則向所有正在執行的執行緒發出中斷訊號以嘗試終止執行緒,並將工作佇列中的任務以列表方式的結果返回。

兩者區別:

  • 是一個要將執行緒池推到SHUTDOWN狀態,一個將推到STOP狀態
  • 並且對執行的執行緒處理方式不同,shutdown()只中斷空閒執行緒,而shutdownNow()會嘗試中斷所有活動執行緒
  • 還有就是對佇列中的任務處理,shutdown()佇列中已有任務會繼續執行,而shutdownNow()會直接取出不被執行

相同的是都在最後嘗試將執行緒池推到TERMINATED狀態。

4. ThreadPoolExecutor的awaitTermination()

阻塞等待shutdown請求後所有執行緒終止,會有時間引數,超時和中斷也會令方法呼叫結束。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public boolean awaitTermination(long timeout, TimeUnit unit)
    throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        for (;;) {
            if (runStateAtLeast(ctl.get(), TERMINATED))
                return true;
            if (nanos <= 0)
                return false;
            nanos = termination.awaitNanos(nanos);
        }
    } finally {
        mainLock.unlock();
    }
}

實際所做的就是Condition的定時await呼叫。用於狀態依賴的執行緒阻塞。

5. tryTerminate()

tryTerminate()的意義就在於嘗試進入終止狀態,當ctl中worker數字為0時執行terminated()方法,否則等鎖中斷一個空閒的Worker。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
final void tryTerminate() {
    for (;;) {
        int c = ctl.get();
        if (isRunning(c) ||
            runStateAtLeast(c, TIDYING) ||
            (runStateOf(c) == SHUTDOWN && ! workQueue.isEmpty()))
            return;
        if (workerCountOf(c) != 0) { // Eligible to terminate
            interruptIdleWorkers(ONLY_ONE);
            return;
        }
 
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) {
                try {
                    terminated();
                } finally {
                    ctl.set(ctlOf(TERMINATED, 0));
                    termination.signalAll();
                }
                return;
            }
        } finally {
            mainLock.unlock();
        }
        // else retry on failed CAS
    }
}

其中interruptIdleWorkers()方法這裡就不列程式碼了,空閒的worker主要是通過worker的tryLock()來確認的,因為執行任務的worker互斥地鎖定物件。

中斷worker導致執行緒退出,最終還會迴圈嘗試終止其它的空閒執行緒,直到整個ThreadPoolExecutor最後終結。

6. ThreadPoolExecutor生命週期的擴充套件點

在生命週期上,ThreadPoolExecutor為擴充套件的類提供了一些擴充套件點,這是很好的設計,對擴充套件開放。

其中宣告瞭如下protected的方法:

  • beforeExecute() 在每個任務執行前做的處理
  • afterExecute() 在每個任務執行後做的處理
  • terminated() 在ThreadPoolExecutor到達TERMINATED狀態前所做的處理
  • finalize() 有預設實現,直接呼叫shutdown(),以保證執行緒池物件回收
  • onShutdown() 在shutdown()方法執行到最後時呼叫,在java.util.concurrent.ScheduledThreadPoolExecutor類實現中用到了這個擴充套件點,做一些任務佇列的清理操作。

相關文章