Java線程池之ThreadPoolExecutor源碼解析

目錄

0、引言

0.1任務隊列: LinkedBlockingQueue 沒有設置固定容量大小

0.2最大線程數量是: Integer.MAX_VALUE

0.3拒絕策略:不能自定義

1、ThreadPoolExecutor

1.1基本架構

1.2提交方法源碼解析

1.3線程的管理解析


0、引言

爲甚麼線程池不允許使用Executors去創建,而是通過ThreadPoolExecutor的方式?

0.1任務隊列: LinkedBlockingQueue 沒有設置固定容量大小

//例如
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

newFixedThreadPool()、newSingleThreadExecutor() 底層代碼 中 LinkedBlockingQueue 沒有設置容量大小,默認是 Integer.MAX_VALUE, 可以認爲是無界的。線程池中 多餘的線程會被緩存到 LinkedBlockingQueue中,最終內存撐爆。

0.2最大線程數量是: Integer.MAX_VALUE

//例如
public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}

newCachedThreadPool()、newScheduledThreadPool() 的 底層代碼 中 的 最大線程數(maximumPoolSize) 是 Integer.MAX_VALUE,可以認爲是無限大,如果線程池中,執行中的線程沒有及時結束,並且不斷地有線程加入並執行,最終會將內存撐爆。

0.3拒絕策略:不能自定義

//Executors 底層其實是使用的 ThreadPoolExecutor 的方式 創建的,但是使用的是 ThreadPoolExecutor 的默認策略
//默認策略
 private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();
//構造函數
public ThreadPoolExecutor(int corePoolSize,
                             int maximumPoolSize,
                             long keepAliveTime,
                             TimeUnit unit,
                             BlockingQueue<Runnable> workQueue) {
	this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
            Executors.defaultThreadFactory(), defaultHandler);
}

 


1、ThreadPoolExecutor


1.1基本架構

  • ThreadPoolExecutor(類)-AbstractExecutorService(抽象類)-ExecutorService(接口)-Executor(接口)
  • Executor 定義 execute 方法來執行任務,入參是 Runnable
public interface Executor {
    void execute(Runnable command);
}
  • ExecutorService 豐富了對任務的執行和管理的功能
// 關閉,不會接受新的任務,也不會等待未完成的任務
void shutdown();
// executor 是否已經關閉了,返回值 true 表示已關閉
boolean isShutdown();
// 所有的任務是否都已經終止,是的話,返回 true
boolean isTerminated();
// 在超時時間內,等待剩餘的任務終止
boolean awaitTermination(long timeout, TimeUnit unit)
    throws InterruptedException;
// 提交有返回值的任務,使用 get 方法可以阻塞等待任務的執行結果返回
<T> Future<T> submit(Callable<T> task);
// 提交沒有返回值的任務,如果使用 get 方法的話,任務執行完之後得到的是 null 值
Future<?> submit(Runnable task);
// 給定任務集合,返回已經執行完成的 Future 集合,每個返回的 Future 都是 isDone = true 的狀態
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
    throws InterruptedException;
// 給定任務中有一個執行成功就返回,如果拋異常,其餘未完成的任務將被取消
<T> T invokeAny(Collection<? extends Callable<T>> tasks)
    throws InterruptedException, ExecutionException;
  • AbstractExecutorService 是一個抽象類,封裝了 Executor 的很多通用功能
// 把 Runnable 轉化成 RunnableFuture
// RunnableFuture 是一個接口,繼承了 Runnable 和 Future
// FutureTask 是 RunnableFuture 的實現類,主要是對任務進行各種管理
// Runnable + Future => RunnableFuture => FutureTask
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}
// submit也是我們平時線程池提交任務的方法
// 提交無返回值的任務
public Future<?> submit(Runnable task) {
    if (task == null) throw new NullPointerException();
    // ftask 其實是 FutureTask
    RunnableFuture<Void> ftask = newTaskFor(task, null);
    execute(ftask);// 子類ThreadPoolExecutor實現的
    return ftask;
}
// 提交有返回值的任務
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    // ftask 其實是 FutureTask
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);// 子類ThreadPoolExecutor實現的
    return ftask;
}
// 任務轉化爲FutureTask
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
    return new FutureTask<T>(runnable, value);
}

1.2提交方法源碼解析

  • 提交 Runnable 和 Callable 任務並且都轉化成 FutureTask(是實際的任務類型);
  • 使用父類的submit方法進行實際的流程,返回Future任務;
  • 使用 execute 方法是線程池的主流程;
public void execute(Runnable command) {
    if (command == null)
        throw new NullPointerException();
    int c = ctl.get();
    // 1.工作的線程小於核心線程數,創建新的線程,成功返回,失敗不拋異常
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        // 線程池狀態可能發生變化
        c = ctl.get();
    }
    // 2.線程池狀態正常,並且可以入隊的話,嘗試入隊列
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        // 如果線程池狀態異常 嘗試從隊列中移除任務,可以移除的話就拒絕掉任務
        if (!isRunning(recheck) && remove(command))
            reject(command);
        // 發現可運行的線程數是 0,就初始化一個線程,這裏是個極限情況,入隊的時候,突然發現
        // 可用線程都被回收了
        else if (workerCountOf(recheck) == 0)
            // Runnable是空的,不會影響新增線程,但是線程在 start 的時候不會運行
            // Thread.run() 裏面有判斷
            addWorker(null, false);
    }
    // 3.隊列滿了,開啓線程到 maxSize,4.如果失敗進行拒絕策略,
    else if (!addWorker(command, false))
        reject(command);
}
  • execute裏面多次調用了addWork方法,
// 結合線程池的情況看是否可以添加新的 worker
// firstTask 不爲空可以直接執行,爲空執行不了,Thread.run()方法有判斷,Runnable爲空不執行
// core 爲 true 表示線程最大新增個數是 coresize,false 表示最大新增個數是 maxsize
// 返回 true 代表成功,false 失敗
// break retry 跳到retry處,且不再進入循環
// continue retry 跳到retry處,且再次進入循環
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    // 先是各種狀態的校驗
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        // Check if queue empty only if necessary.
        // rs >= SHUTDOWN 說明線程池狀態不正常
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        for (;;) {
            int wc = workerCountOf(c);
            // 工作中的線程數大於等於容量,或者大於等於 coreSize or maxSize
            if (wc >= CAPACITY ||
                wc >= (core ? corePoolSize : maximumPoolSize))
                return false;
            if (compareAndIncrementWorkerCount(c))
                // break 結束 retry 的 for 循環
                break retry;
            c = ctl.get();  // Re-read ctl
            // 線程池狀態被更改
            if (runStateOf(c) != rs)
                // 跳轉到retry位置
                continue retry;
        }
    }
    //開始進行進行創建work並且start執行
    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 巧妙的設計,Worker 本身是個 Runnable.
        // 在初始化的過程中,會把 worker 丟給 thread 去初始化
        w = new Worker(firstTask);
        final Thread t = w.thread;
        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());
                if (rs < SHUTDOWN ||
                    (rs == SHUTDOWN && firstTask == null)) {
                    if (t.isAlive()) // precheck that t is startable
                        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;
}

首選進行了各種條件的驗證,然後將任務加入,並且通過Worker類獲取對應任務的線程,並且啓動線程start

  • addWork方法裏創建了Work類,並且進行執行線程start
// 線程池中任務執行的最小單元
// Worker 繼承 AQS,具有鎖功能
// Worker 實現 Runnable接口,run方法對應外部的runWorker方法,所有本身是一個可執行的任務
private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable 
{
    // 任務運行的線程
    final Thread thread;
    // 需要執行的任務
    Runnable firstTask;
    // 非常巧妙的設計,Worker本身是個 Runnable,把自己作爲任務傳遞給 thread
    // 初始化線程
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        // 把 Worker 自己作爲 thread 運行的任務
        this.thread = getThreadFactory().newThread(this);
    }
    public void run() {
        runWorker(this);// 外部方法,Worker是內部類,ThreadPoolExecutor是類
    }
    private static final long serialVersionUID = 6138294804551838833L;
    // Lock methods
    // 0 代表沒有鎖住,1 代表鎖住
    protected boolean isHeldExclusively() {
        return getState() != 0;
    }
    // 嘗試加鎖,CAS 賦值爲 1,表示鎖住
    protected boolean tryAcquire(int unused) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }
    // 嘗試釋放鎖,釋放鎖沒有 CAS 校驗,可以任意的釋放鎖
    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;
        if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
            try {
                t.interrupt();
            } catch (SecurityException ignore) {
            }
        }
    }
}
  • run方法裏又調用了runWorker方法
final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    //幫助gc回收
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        // 就是,在這裏進行線程的具體管理,而不是實際消亡
        // task 爲空的情況:
        // 1:任務入隊列了,極限情況下,發現沒有運行的線程,於是新增一個線程;
        // 2:線程執行完任務執行,再次回到 while 循環。
        // 如果 task 爲空,會使用 getTask 方法阻塞從隊列中拿數據,如果拿不到數據,會阻塞住
        while (task != null || (task = getTask()) != null) {
            //鎖住 worker
            w.lock();
            // 線程池 stop 中,但是線程沒有到達中斷狀態,幫助線程中斷
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                //執行 before 鉤子函數
                beforeExecute(wt, task);
                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 {
                    //執行 after 鉤子函數,如果這裏拋出異常,會覆蓋 catch 的異常
                    //所以這裏異常最好不要拋出來
                    afterExecute(task, thrown);
                }
            } finally {
                //任務執行完成,計算解鎖
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        //做一些拋出異常的善後工作
        processWorkerExit(w, completedAbruptly);
    }
}

runWorker,主要就是使用當前線程執行任務的run方法,並且配有執行前和執行後的鉤子函數處理!

  • runWorker裏調用了run方法
public void run() {
    // 狀態不是任務創建,或者當前任務已經有線程在執行了
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        // Callable 不爲空,並且已經初始化完成
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                // 調用執行
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            // 給 outcome 賦值
            if (ran)
                set(result);
        }
    } finally {
        runner = null;
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

run方法裏實際是執行FutureTask任務的call方法並且把返回值進行賦值

  • 整體流程:

@ThreadPoolExecute執行上層抽象類的submit方法,@submit裏先將任務封裝成FutureTask任務,在執行execute方法

@execute方法裏實際又新創建一個Worker類(繼承AQS,並且實現了Runnable接口)封裝任務然後進行addWorker加入

@addWorker裏先進行了狀態驗證,然後加入任務,在獲取到Worker類對應的線程並且start啓動,創建線程執行run方法

@Worker類裏的run方法,調用了runWorker方法,該方法調用FutureTask任務的run方法並加入了執行前/後進行處理

@FutuerTask任務的run實際是調用任務的call方法並且將返回值進行設置

1.3線程的管理解析

  • 實際入口在runWorker函數裏面的getTask方法裏
....
while (task != null || (task = getTask()) != null) {
            //鎖住 worker
            w.lock();
....
// 從阻塞隊列中拿任務
private Runnable getTask() {
    boolean timedOut = false;
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
        //線程池關閉 && 隊列爲空,不需要在運行了,直接放回
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            decrementWorkerCount();
            return null;
        }
        // 釋放線程
        int wc = workerCountOf(c);
        // true  運行的線程數大於 coreSize || 核心線程也可以被滅亡
        boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
        // 隊列以 LinkedBlockingQueue 爲例,timedOut 爲 true 的話說明下面 poll 方法執行返回的是 null
        // 說明在等待 keepAliveTime 時間後,隊列中仍然沒有數據
        // 再加上 wc > 1 || workQueue.isEmpty() 的判斷,說明此線程已經空閒了 keepAliveTime 了
        // 所以使用 compareAndDecrementWorkerCount 方法使線程池數量減少 1
        // 並且直接 return,return 之後,此空閒的線程會自動被回收
        if ((wc > maximumPoolSize || (timed && timedOut))
            && (wc > 1 || workQueue.isEmpty())) {
            if (compareAndDecrementWorkerCount(c))
                return null;
            continue;
        }
        // 線程獲取任務
        try {
            // 從隊列中阻塞拿 worker
            Runnable r = timed ?
                workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                workQueue.take();
            if (r != null)
                return r;
            // 設置已超時,說明此時隊列沒有數據
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}

無限循環,管理線程的消亡和任務的獲取(可以通過無限阻塞的take,也可以使用設置超時的poll)

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