ThreadPoolExecutor源碼解析

ThreadPoolExecutor 代碼解析

本文源碼解析基於JDK1.8
本人愚見,若有錯誤,請指正,謝謝

ThreadPoolExecutor是Java中的線程池的核心類。用Executors創建的線程池本質也是用的該類,定時任務用到的ScheduleThreadPoolExecutor是繼承於此類。

Executor的初始化

ThreadPoolExecutor的變量和常量

ThreadPoolExecutor定義了一個原子類對象ctl,用來保存線程池的狀態和線程池的線程數量。Integer數據類型長度有32位,ctl將高位3位保存狀態標誌,低位29位保存worker數量。初始化後,默認狀態是RUNNING,線程數量是0。

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1;

// 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;

COUNT_BITS是worker數量所佔用的位數,此處爲29。
CAPACITY 是worker的最大數量,229 -1=536870911,二進制表示爲00011111111111111111111111111111。
線程池共有5個狀態:狀態由ctl的高三位保存。

狀態 狀態位 描述
RUNNING 111 線程池初始化後的默認狀態,接收並處理任務
SHUTDOWN 000 調用shutdown()方法後的狀態,拒絕接收任務,但會處理隊列中的任務
STOP 001 調用shutdownNow()方法後的狀態,拒絕接收任務,同時中斷正在運行的任務
TIDYING 010 工作隊列爲空,同時線程數量爲0時的狀態,有個terminated()的hook
TERMINATED 011 線程池停止

ThreadPoolExecutor的構造器

ThreadPoolExecutor共有4個構造器,最根本的是參數最多的那個。此構造器參數有7位,分別是:

參數名 描述
corePoolSize 核心線程池大小,核心線程是指在空閒情況下依然能存活的線程,除非allowCoreThreadTimeOut()設置爲true
maximumPoolSize 線程池持有的最大線程數量
keepAliveTime 線程存活時間,當線程數量大於corePoolSize時,空閒線程在關閉前等待task的最大時間
unit 線程存活時間單位,keepAliveTime的單位
workQueue 用來暫時保存任務的隊列
threadFactory 線程工廠,executor創建thread的工廠
handler 當ThreadPoolExecutor關閉或ThreadPoolExecutor已經飽和時,execute()調用的飽和策略

源碼如下:

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler) {
    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;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}

類中還有個變量allowCoreThreadTimeOut,用來設置coreThread是否可以在空閒時超時關閉,需要用allowCoreThreadTimeOut方法來設置。

public void allowCoreThreadTimeOut(boolean value) {
    if (value && keepAliveTime <= 0)
        throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
    if (value != allowCoreThreadTimeOut) {
        allowCoreThreadTimeOut = value;
        if (value)
            interruptIdleWorkers();
    }
}

調用execute()方法提交任務

ThreadPoolExecutor可以使用submit()或者execute()方法提交任務,區別在於submit()可以提交Callable的任務,就是帶有返回值的任務,但是callable對象會被包裝成runnable對象,還是調用execute()。

public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();

    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    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);
    }    
    else if (!addWorker(command, false))
        reject(command);
}

一個task提交後,線程池的處理流程如下:
1. 核心線程池還未滿,則創建一個新的核心線程執行任務。新建核心線程成功,方法結束返回。如果失敗,則獲取新的ctl值,進入步驟2。
2. 判斷線程池是在運行且成功添加任務到工作隊列中,則獲取新的ctl,再次判斷狀態。如果狀態爲非運行,且成功從工作隊列中移出任務,則拒絕任務。如果是運行狀態或者移除任務失敗,移出任務失敗說明此任務可能被執行或者遇到shutdownNow()方法,任務被移除隊列,運行狀態的話,這裏判斷線程數量爲0(不理解),添加一個非核心線程。
3. 如果任務無法加到工作隊列中,或者線程池不在運行狀態:如果是線程池關閉,則不考慮後續;如果是工作隊列已滿,則添加非核心線程處理任務。如果線程池已滿,無法添加非核心線程,則拒絕任務。

工作線程Worker

工作線程Worker類

工作線程Worker是ThreadPoolExecutor的內部類,繼承了AbstractQueuedSynchronizer,封裝了線程和任務,並且維護了一個state狀態。state在初始化時是-1,防止在工作線程還未運行時,就被interrupts。在開始運行時,設置爲0。並且在執行任務開始前後分別設置爲1,0,等待task時的state是0,目的是將正在運行task和等待task的worker區別開,以便在修改線程池參數或者shutdown時可以interrupt等待任務的worker。

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable
{
    final Thread thread;
    volatile long completedTasks;
    Worker(Runnable firstTask) {
        setState(-1); // 設置state爲-1,防止線程還未start,就被interrupt
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
    public void run() {
        runWorker(this);
    }
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }

    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }

    protected boolean tryRelease(int unused) {
        setExclusiveOwnerThread(null);
        setState(0);
        return true;
    }

    public void lock()        { acquire(1); }
    public boolean tryLock()  { return tryAcquire(1); }
    public void unlock()      { release(1); }
    public boolean isLocked() { return isHeldExclusively(); }

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

worker的創建

addWorker()方法用來添加工作線程。

private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            // 上述的rs >= SHUTDOWN && !(rs==shutdown && firstTask==null && !workQueue.isEmpty())可以推導爲
            // rs >= SHUTDOWN && (rs!=shutdown || firstTask!=null || workQueue.isEmpty())
            // 也就是:
            // 線程池在running狀態,添加工作線程
            // 線程池在shutdown狀態下,firstTask不爲空,不添加工作線程,此處返回false,應該是要reject。
            // 線程池在shutdown狀態下,firstTask爲空,workQueue爲空時,不添加工作線程,換句話說workQueue不爲空時,可以添加線程加快處理速度。
            // 線程池在stop,tidying,terminated狀態下,不添加工作線程
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            // 當前線程池的工作線程數量達到最大數量,或者核心線程數量或最大線程數量達到上限,返回false。
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            // 原子類的CAS操作
            // 工作線程數+1,如果狀態改變或者工作線程數變化,則CAS更新失敗
            if (compareAndIncrementWorkerCount(c))
                break retry;
            c = ctl.get();  // Re-read ctl
            // 如果狀態不變,就自循環增加wc,如果狀態變了,就需要重新判斷狀態。
            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,用threadFactory創建新的線程
        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);
                    // 更新同一時間最多用到多少個線程largestPoolSize
                    int s = workers.size();
                    if (s > largestPoolSize) 
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

worker的運行

其中的run()方法調用runWorker()方法就是執行task的方法了。

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true; 
    try {
    //任務爲空時,則到工作隊列中取任務
        while (task != null || (task = getTask()) != null) {
            w.lock();           
            // 如果線程池在STOP及之後狀態,而且線程不是中斷的,則中斷線程
            // 因爲有可能調用shutdownNow(),所以這裏有第二次檢查,也是檢查線程池狀態,Thread.interrupted()是用來判斷線程是否中斷,同時清除中斷標誌。
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task); // hook
                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); // hook
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        // 如果task爲null,或者task順利執行完,設置爲false;如果task報錯,爲true
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

worker的晚年

worker有幾種結束的情況:
1. 線程池調用shutdownNow(),中斷線程退出。這種情況就不會新建線程。
2. 任務報錯退出,如果線程池在RUNNING和shutdown狀態,會新建一個線程繼續處理任務。
3. 正常運行結束,因爲while循環會一直拿task,所以正常結束意味着沒任務或者STOP狀態不給任務。如果當前線程數能滿足要求(核心線程數或者1個線程),則不創建新線程。
worker結束後,從workers裏移除,並嘗試關閉線程池。

//worker最後的時光
private void processWorkerExit(Worker w, boolean completedAbruptly) {
    if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
        decrementWorkerCount();

    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        completedTaskCount += w.completedTasks;
        workers.remove(w);
    } finally {
        mainLock.unlock();
    }

    tryTerminate();

    int c = ctl.get();
    if (runStateLessThan(c, STOP)) {
        if (!completedAbruptly) {
            int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
            if (min == 0 && ! workQueue.isEmpty())
                min = 1;
            if (workerCountOf(c) >= min)
                return; // replacement not needed
        }
        addWorker(null, false);
    }
}

worker獲取食物

getTask()用於獲取任務

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

    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }

        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 {
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

getTask()是獲取任務的方法,線程空閒時間超時也是這裏控制的。有幾種情況是拿不到task的:
1. 線程池是stop狀態
2. 線程池是shutdown狀態,並且工作隊列爲null。
3. 線程數大於maximumPoolSize,在變更maximumPoolSize參數後,有可能發生。
4. 線程數大於corePoolSize,並且超時
5. 在allowCoreThreadTimeOut 爲true時,線程數大於1,並且獲取task超時。
6. 在allowCoreThreadTimeOut 爲true時,工作隊列沒有task,並且獲取task超時。
在拿不到task的情況,會將線程數-1,並且return null。

線程池的終結

馬上終結

shutdownNow()用來立刻結束線程池,中斷所有線程,並且返回還未執行的任務。
終結的步驟:
1. 檢查shutdown的權限,調用其他thread的interrupt方法需要權限。
2. 設置線程池狀態爲stop,如果線程池狀態已經是STOP,TIDYING,TERMINATED,則不更改。
3. 中斷所有工作線程。
4. 取出尚未執行的任務作爲返回值。
5. 調用tryTerminate結束線程池。

public List<Runnable> shutdownNow() {
    List<Runnable> tasks;
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(STOP);
        interruptWorkers();
        tasks = drainQueue();
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
    return tasks;
}

慢慢終結

shutdown()方法用來有計劃地結束線程池:
1. 首先拒絕接收新任務。
2. 然後檢查shutdown權限
3. 設置線程池狀態爲shutdown
4. 中斷所有空閒線程
5. 執行完所有任務後,才真正結束線程池。

public void shutdown() {
    final ReentrantLock mainLock = this.mainLock;
    mainLock.lock();
    try {
        checkShutdownAccess();
        advanceRunState(SHUTDOWN);
        interruptIdleWorkers();
        onShutdown(); // hook for ScheduledThreadPoolExecutor
    } finally {
        mainLock.unlock();
    }
    tryTerminate();
}

真正關閉線程池的主角

tryTerminate()這個方法會真正將線程池設置爲terminated狀態。
步驟:
1. RUNNING,TIDYING,TERMINATED狀態直接返回,shutdown狀態下還有任務的情況下,返回
2. 工作線程數量不爲0時,中斷空閒線程,返回
3. 1和2都不滿足的情況下,設置線程池狀態爲TIDYING
4. 調用terminated()方法,這是個hook,爲TIDYING準備的
5. 設置狀態爲TERMINATED,

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
        }
    }

在調用shutdown, shutdownNow後,並不是方法結束,線程池就結束的,所以tryTerminate方法在其他方法中也有調用:
1. addWorkerFailed(),這個方法是在增加工作線程失敗時調用
2. processWorkerExit(),工作線程結束時調用
3. shutdown()
4. shutdownNow()
5. remove(),這個方法用來刪除任務
6. purge(),這個方法用來移除工作隊列中的Callable任務

等待終結

Executor提供了一個方法awaitTermination,用來判斷在指定時間內,線程池有沒有關閉。

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();
    }
}

finalize()

在線程池不被引用,而且沒有線程時,GC會清理掉這個對象,在清理之前會調用這個方法。

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