Java併發——深入 ThreadPoolExecutor 任務執行原理

1 Executor

它用於執行指定的任務,把任務提交與任務執行分離,程序員不需要關注線程的管理,以及任務的執行。
ExecutorService 接口對 Executor 接口提供更多的擴展,ThreadPoolExecutor 類提供
可以擴展的線程池實現,而 Executors 只是對這些 Executor 提供方便的工廠方法。

1.1 類圖

Executor

2 Future

2.1 類圖

Future

2.2 FutureTask

類結構:

class FutureTask {
    // 任務運行狀態
    /*
     * NEW -> COMPLETING -> NORMAL
     * NEW -> COMPLETING -> EXCEPTIONAL
     * NEW -> CANCELLED
     * NEW -> INTERRUPTING -> INTERRUPTED
     */
    private volatile int state;
    private static final int NEW          = 0;
    private static final int COMPLETING   = 1;
    private static final int NORMAL       = 2;
    private static final int EXCEPTIONAL  = 3;
    private static final int CANCELLED    = 4;
    private static final int INTERRUPTING = 5;
    private static final int INTERRUPTED  = 6;
    
    // 底層運行的 callable
    private Callable<V> callable;
    // 任務結果,非 volatile,因爲受 state 讀寫保護
    private Object outcome;
    // 運行 callable 任務的線程
    private volatile Thread runner;
    
    private volatile WaitNode waiters;
    
    //  在 Treiber stack 中記錄等待中的線程
    static final class WaitNode {
        volatile Thread thread;
        volatile WaitNode next;
        WaitNode() { thread = Thread.currentThread(); }
    }
}

兩個重要的構造函數:

// 包裝 Callable,state = NEW
public FutureTask(Callable<V> callable) {
    if (callable == null)
        throw new NullPointerException();
    this.callable = callable;
    this.state = NEW;
}

public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

第二個構造器使用了 Executors 工具類的 callable() 方法來把 Runnable 適配成 Callable。典型的
適配器模式。

public static <T> Callable<T> callable(Runnable task, T result) {
    return new RunnableAdapter<T>(task, result);
}

static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

3 ThreadPoolExecutor

3.1 類結構

class ThreadPoolExecutor {
    // 狀態控制,包含兩個信息:
    // workerCount: 工作線程數
    // runState: 表明線程池運行狀態
    //     RUNNING: 可以接受新的 task,且能處理隊列中的 task
    //     SHUTDOWN: 不接受新的 task,但能處理隊列中的 task
    //     STOP: 不接受新的 task,不處理隊列中的 task,並且中斷運行中的 task
    //     TIDYING: 所有任務都被終止,workerCount = 0,線程狀態爲 TIDYING
    //     TERMINATED: terminated() 方法執行完成
    //                  RUNNING
    //       shutdownNow()|    \ shutdown()
    //                    |/    \/
    //                 STOP---- SHUTDOWN
    //            線程池爲空|       / 隊列和線程池都爲空
    //                    |/    \/          \
    //                    TIDYING------------- TERMINATED
    //                            terminated()
    // 初始化:ctl = RUNNING
    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
    // 11101
    private static final int COUNT_BITS = Integer.SIZE - 3;
    // 00011111111111111111111111111111  536870911
    // worker 線程最大數量
    private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

    // runState 存儲在高位
    // 111 開頭 -536870912
    private static final int RUNNING    = -1 << COUNT_BITS;
    // 000 開頭 0
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    // 001 開頭 536870912
    private static final int STOP       =  1 << COUNT_BITS;
    // 010 開頭 1073741824
    private static final int TIDYING    =  2 << COUNT_BITS;
    // 011 開頭 1610612736
    private static final int TERMINATED =  3 << COUNT_BITS;

    // ~CAPACITY = 11100000000000000000000000000000
    private static int runStateOf(int c)     { return c & ~CAPACITY; }

    private static int workerCountOf(int c)  { return c & CAPACITY; }

    private static int ctlOf(int rs, int wc) { return rs | wc; }

    private static boolean runStateLessThan(int c, int s) {
        return c < s;
    }

    private static boolean runStateAtLeast(int c, int s) {
        return c >= s;
    }

    private static boolean isRunning(int c) {
        return c < SHUTDOWN;
    }
}

3.2 內部類 Worker

private final class Worker extends AbstractQueuedSynchronizer
        implements Runnable {
    // 執行任務線程
    final Thread thread;
    // 待執行任務
    Runnable firstTask;
    // 每個線程完成任務數
    volatile long completedTasks;
    
    Worker(Runnable firstTask) {
        setState(-1); // 設置AQS的同步狀態爲-1,禁止中斷,直到調用 runWorker
        this.firstTask = firstTask;
        // 使用 ThreadFactory 創建線程
        this.thread = getThreadFactory().newThread(this);
    }
    
    /** Delegates main run loop to outer runWorker  */
    public void run() {
        // 核心
        runWorker(this);
    }
}

3.3 任務執行(execute)

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    // 初始時,ctl = RUNNING = 11100000000000000000000000000000
    int c = ctl.get();
    // wokerCountOf(c) => c & 00011111111111111111111111111111
    // 線程數小於 corePoolSize,創建線程執行 task
    if (workerCountOf(c) < corePoolSize) {
        // 創建線程,並啓動線程執行 command
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }

    // 兩種情況:
    // ① 線程數大於等於 corePoolSize;
    // ② 線程數小於 corePoolSize,但是 addWorker() 線程池狀態不符合條件,或創建線程失敗或啓動線程失敗
    // 線程池處於運行狀態才能往隊列添加任務
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        if (! isRunning(recheck) && remove(command))
            reject(command);
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    // 線程池非 RUNNING 狀態
    // 隊列已滿
    // 此時使用 maximumPoolSize 作爲界限判斷
    else if (!addWorker(command, false))
        reject(command);
}

/**
 * addWoker() 方法返回 false 幾種情況:
 *    1)線程池停止或 shutdown 
 *    2)ThreadFactory 創建線程失敗
 * @param core true:使用 corePoolSize 作爲界限;false:使用 maximumPoolSize 作爲界限
 */
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        
        // ① 線程池狀態是 RUNNING,可以創建工作線程,即執行下面的 for 循環
        // ② 線程池狀態是 STOP、TIDYING 或 TERMINATED,直接返回 false,即不能創建工作線程執行任務
        // ③ 線程池狀態時 SHUTDOWN,此時 firstTask 在此種狀態下應該爲 null,即它不能接收新的任務
        // 所以如果 firstTask 不爲 null,那麼可以直接返回 false
        // 如果 firstTask 爲 null,此時線程池可以處理隊列中任務,所以如果隊列爲空,那麼直接返回 false,否則需要創建工作線程處理隊列中的任務
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;
        
        // runState 爲 RUNNING 或 SHUTDOWN
        for (;;) {
            int wc = workerCountOf(c);
            // woker 線程數超過界限,返回 false
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
 
            // CAS 增加 workerCount
            if (compareAndIncrementWorkerCount(c))
                break retry; // 失敗
            c = ctl.get();  // Re-read ctl
            // 可能 runState 被其他線程改變,非 RUNNING 或 SHUTDOWN 狀態
            if (runStateOf(c) != rs)
                continue retry;
            // else CAS failed due to workerCount change; retry inner loop
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 初始化 Worker,創建線程
        w = new Worker(firstTask);
        final Thread t = w.thread;
        
        if (t != null) { // 線程創建成功
            // 全局鎖
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                // 再次檢查線程池的運行狀態等
                int rs = runStateOf(ctl.get());

                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) 
                        // 線程處於活躍狀態,即線程已經開始執行或者還未死亡,正確的應線程在這裏應該是還未開始執行的
                        throw new IllegalThreadStateException();
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                // 實際會調用 Worker 類的 run() 方法
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted) //未能成功創建執行工作線程
            addWorkerFailed(w);  //在啓動工作線程失敗後,將工作線程從集合中移除
    }
    return workerStarted;
}

從上述代碼分析可以看出,有很多書上在分析線程池的執行原理是有問題的。
線程池工作原理
小結上述邏輯:

  • 線程池控制標識是原子類型,即 AtomicInteger
  • execute() 方法只關注線程池核心工作流程,具體執行細節交由其他方法處理,主要是 addWorker() 方法
  • 工作線程小於 corePoolSize 時,創建工作線程以及執行任務統一交給 addWorker() 方法處理
  • addWorker() 方法在創建工作線程執行任務之前,需要判斷線程池當前狀態是否滿足可以創建工作線程。
    • RUNNING 狀態可以接收新的任務(能創建工作線程),且能處理隊列中的任務
    • SHUTDOWN 狀態不能接收新的任務(不能創建工作線程),但能處理隊列中的任務
  • 使用 CAS 計數工作線程,即更新線程池控制標識
  • 任務和線程統一由其內部類 Worker 進行封裝,Worker 類本身也是 Runnable

整個流程圖如下,畫的不太好,主要還是爲了梳理邏輯,因爲整個代碼用到了太多 if() 語句的短路思維,當然這些主要是跟線程池的狀態有關。
線程執行任務流程圖

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章