ThreadPoolExecutor源碼解析

原文地址:http://www.cnblogs.com/java-zhao/p/5147811.html

1、源代碼主要掌握兩個部分

  • 線程池的創建:構造器
  • 提交任務到線程池去執行:execute()

 

2、構造器

2.1、一些屬性:

複製代碼
    /**
     * runState provides the main lifecyle control, taking on values:
     *
     * RUNNING -> SHUTDOWN
     *    On invocation of shutdown(), perhaps implicitly in finalize()
     * (RUNNING or SHUTDOWN) -> STOP
     *    On invocation of shutdownNow()
     * SHUTDOWN -> TERMINATED
     *    When both queue and pool are empty
     * STOP -> TERMINATED
     *    When pool is empty
     */
    volatile int runState;
    static final int RUNNING    = 0;//接收新的任務,會處理隊列中的任務
    static final int SHUTDOWN   = 1;//不接收新的任務,但是會處理隊列中的任務
    static final int STOP       = 2;//不接收新的任務,也不會處理隊列中的任務,而且還會中斷正在執行的任務
    static final int TERMINATED = 3;//STOP+中止所有線程

    private final BlockingQueue<Runnable> workQueue;//隊列

    /**
     * 對poolSize, corePoolSize, maximumPoolSize, runState, and workers set上鎖
     */
    private final ReentrantLock mainLock = new ReentrantLock();

    /**
     * 支持awaitTermination的等待條件
     */
    private final Condition termination = mainLock.newCondition();

    /**
     * pool中的所有工作線程集合;僅僅在持有mainLock的時候才允許被訪問
     */
    private final HashSet<Worker> workers = new HashSet<Worker>();

    private volatile long  keepAliveTime;

    /**
     * false(默認):當核心線程處於閒置狀態時,也會存活
     * true:核心線程使用keepAliveTime來決定自己的存活狀態
     */
    private volatile boolean allowCoreThreadTimeOut;

    /**
     * Core pool size,僅僅在持有mainLock的時候才允許被更新, 
     * 因爲是volatile允許併發讀(即使是在更新的過程中)
     */
    private volatile int   corePoolSize;

    /**
     * Maximum pool size, 其他同上
     */
    private volatile int   maximumPoolSize;

    /**
     * Current pool size, 其他同上
     */
    private volatile int   poolSize;

    /**
     * 回絕處理器
     */
    private volatile RejectedExecutionHandler handler;

    /**
     * 所有的線程都通過這個線程工廠的addThread方法來創建。
     */
    private volatile ThreadFactory threadFactory;

    /**
     * Tracks largest attained pool size.
     */
    private int largestPoolSize;

    /**
     * 已經完成的任務數.僅僅在工作線程被終結的時候這個數字纔會被更新 
     */
    private long completedTaskCount;

    /**
     * 默認的回絕處理器(回絕任務並拋出異常)
     */
    private static final RejectedExecutionHandler defaultHandler =
        new AbortPolicy();
複製代碼

說明:因爲屬性不多,這裏列出了全部屬性。

 

2.2、構造器:

複製代碼
    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             threadFactory, defaultHandler);
    }

    public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              RejectedExecutionHandler handler) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), handler);
    }

    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;
    }
複製代碼

說明:4個構造器(1個5參+2個6參+1個7參)

注意:默認情況下,構造器只會初始化參數,不會提前構建好線程

建議:構造器參數衆多,建議使用構建器模式,關於構建器模式的實際使用範例,請參照《第二章 Google guava cache源碼解析1--構建緩存器

構造器中默認線程工廠的創建:Executors中的方法

複製代碼
    public static ThreadFactory defaultThreadFactory() {
        return new DefaultThreadFactory();
    }

    /**
     * 默認的線程工廠
     */
    static class DefaultThreadFactory implements ThreadFactory {
        static final AtomicInteger poolNumber = new AtomicInteger(1);//池數量
        final ThreadGroup group;//線程組
        final AtomicInteger threadNumber = new AtomicInteger(1);//線程數量
        final String namePrefix;

        /*
         * 創建默認的線程工廠
         */
        DefaultThreadFactory() {
            SecurityManager s = System.getSecurityManager();
            group = (s != null)? s.getThreadGroup() :
                                 Thread.currentThread().getThreadGroup();
            namePrefix = "pool-" +
                          poolNumber.getAndIncrement() +
                         "-thread-";
        }

        /*
         * 創建一個新的線程
         */
        public Thread newThread(Runnable r) {
            Thread t = new Thread(group, r,
                                  namePrefix + threadNumber.getAndIncrement(),//新線程的名字
                                  0);
            /*
             * 將後臺線程設置爲應用線程
             */
            if (t.isDaemon())
                t.setDaemon(false);
            /*
             * 將線程的優先級全部設置爲NORM_PRIORITY
             */
            if (t.getPriority() != Thread.NORM_PRIORITY)
                t.setPriority(Thread.NORM_PRIORITY);
            return t;
        }
    }
複製代碼

說明,其中的newThread()方法會在第三部分用到。

 

3、提交任務的線程池去執行execute(Runnable command)

複製代碼
    public void execute(Runnable command) {
        if (command == null)
            throw new NullPointerException();
        /**
         * 這一塊兒就是整個工作機理的部分(代碼比較精緻)
         * 1、addIfUnderCorePoolSize
         * 1)如果當前線程數poolSize<核心線程數corePoolSize並且pool的狀態爲RUNNING,
         * 1.1)先獲取鎖
         * 1.2)根據傳入的任務firstTask創建一個Work對象,在該對象中編寫了run()方法,在該run()方法中會真正的去執行firstTask的run()
         * 說明:關於Work對象run部分的內容,查看Work內部類的run()方法上邊的註釋以及與其相關方法的註釋
         * 1.3)通過線程工廠與上邊創建出來的work對象w創建新的線程t,將w加入工作線程集合,
         * 然後啓動線程t,之後就會自動執行w中的run(),w中的run()又會調用firstTask的run(),即處理真正的業務邏輯
         * 
         * 2、如果poolSize>=corePoolSize或者上邊的執行失敗了
         * 1)如果pool的狀態處於RUNNING,將該任務入隊(offer(command))
         * 如果入隊後,pool的狀態不是RUNNING了或者池中的線程數爲0了,下邊的邏輯具體去查看註釋
         * 2)addIfUnderMaximumPoolSize(同addIfUnderCorePoolSize)
         * 如果增加線程也不成功,則回絕任務。
         * 
         */
        if (poolSize >= corePoolSize || !addIfUnderCorePoolSize(command)) {
            if (runState == RUNNING && workQueue.offer(command)) {
                if (runState != RUNNING || poolSize == 0)
                    ensureQueuedTaskHandled(command);
            }
            else if (!addIfUnderMaximumPoolSize(command))
                reject(command); // is shutdown or saturated
        }
    }
複製代碼

 

3.1、addIfUnderCorePoolSize(Runnable firstTask)

複製代碼
    /**
     * 創建並且啓動一個新的線程來處理任務
     * 1、其第一個任務就是傳入的firstTask參數
     * 2、該方法僅僅用於當前線程數小於核心線程數並且pool沒有被關掉的時候
     */
    private boolean addIfUnderCorePoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();//獲取鎖
        try {
            if (poolSize < corePoolSize && runState == RUNNING)
                t = addThread(firstTask);//創建新線程
        } finally {
            mainLock.unlock();//釋放鎖
        }
        return t != null;
    }
複製代碼

addThread(Runnable firstTask)

複製代碼
    private Thread addThread(Runnable firstTask) {
        Worker w = new Worker(firstTask);//構造一個work
        Thread t = threadFactory.newThread(w);//創建線程
        boolean workerStarted = false;
        if (t != null) {//
            if (t.isAlive()) //如果t線程已經啓動了,而且還沒有死亡
                throw new IllegalThreadStateException();
            w.thread = t;
            workers.add(w);//將w工作線程加入workers線程池
            int nt = ++poolSize;//當前的池數量+1
            if (nt > largestPoolSize)
                largestPoolSize = nt;
            try {
                t.start();//啓動線程
                workerStarted = true;
            }
            finally {
                if (!workerStarted)//啓動線程沒有成功
                    workers.remove(w);//將w從workers集合中刪除
            }
        }
        return t;
    }
複製代碼

newThread(Runnable r)

該方法在構建上邊的默認線程工廠部分已經說過了。

 

Work內部類:

複製代碼
/**
     * 工作線程。
     */
    private final class Worker implements Runnable {
        /**
         * 在每一個任務的執行前後都會獲取和釋放runLock。
         * 該鎖只要是爲了防止中斷正在執行任務的work線程
         */
        private final ReentrantLock runLock = new ReentrantLock();

        /**
         * Initial task to run before entering run loop. 
         * 1、Possibly null.
         */
        private Runnable firstTask;

        /**
         * 每個work線程完成的任務總量
         * accumulated into completedTaskCount upon termination.
         */
        volatile long completedTasks;

        Thread thread;

        /**
         * 該work中的線程是不是確實正在執行了run()
         */
        volatile boolean hasRun = false;

        Worker(Runnable firstTask) {
            this.firstTask = firstTask;
        }

        /*
         * true:已經有線程持有了該鎖
         */
        boolean isActive() {
            return runLock.isLocked();
        }

        private void runTask(Runnable task) {
            final ReentrantLock runLock = this.runLock;
            runLock.lock();//獲取鎖runLock
            try {
                /*
                 * 如果pool狀態爲STOP或TERMINATED,確保線程被打斷;
                 * 如果不是,確保線程不要被打斷
                 */
                if ((runState >= STOP ||
                    (Thread.interrupted() && runState >= STOP)) &&
                    hasRun)
                    thread.interrupt();
                /*
                 * 確保afterExecute會被執行僅僅當任務完成了(try)或拋出了異常(catch)
                 */
                boolean ran = false;
                beforeExecute(thread, task);//執行任務的run()方法之前要執行的操作
                try {
                    task.run();//執行線程的run()方法
                    ran = true;
                    afterExecute(task, null);//執行任務的run()方法之後要執行的操作
                    ++completedTasks;
                } catch (RuntimeException ex) {
                    if (!ran)
                        afterExecute(task, ex);
                    throw ex;
                }
            } finally {
                runLock.unlock();//釋放鎖runLock
            }
        }

        /**
         * Main run loop
         * 運行當前任務task,運行結束後,嘗試獲取隊列中的其他任務,
         * 如果最後通過各種方式都獲取不到,就回收該線程,如果獲取到了,就用該線程繼續執行接下來的任務
         * 最後,當獲取不到任何任務去執行時,就將該線程從works線程集合中刪除掉
         */
        public void run() {
            try {
                hasRun = true;
                Runnable task = firstTask;
                firstTask = null;
                while (task != null || (task = getTask()) != null) {
                    runTask(task);//運行該任務
                    task = null;
                }
            } finally {
                workerDone(this);//將該線程從works集合中刪除
            }
        }
    }
複製代碼

說明:這裏列出了該內部類的全部屬性和常用方法。

 

getTask()

複製代碼
    /**
     * 獲取下一個worker線程將要運行的任務
     * Gets the next task for a worker thread to run.  
     */
    Runnable getTask() {
        for (;;) {//無限循環
            try {
                int state = runState;
                if (state > SHUTDOWN)
                    return null;
                Runnable r;
                if (state == SHUTDOWN)  // Help drain queue
                    r = workQueue.poll();//處理queue中的任務
                //下面的runState==RUNNING
                else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
                    //從隊頭獲取任務,如果沒有任務,等待keepAliveTime的時間
                    r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
                else
                    //從隊頭獲取任務,如果沒有任務,阻塞等待
                    r = workQueue.take();
                if (r != null)
                    return r;
                if (workerCanExit()) {//允許回收獲取任務失敗的線程
                    if (runState >= SHUTDOWN) // Wake up others
                        interruptIdleWorkers();//中斷閒置的work線程
                    return null;
                }
                // Else retry
            } catch (InterruptedException ie) {
                // On interruption, re-check runState
            }
        }
    }
複製代碼

workerCanExit()

複製代碼
    /**
     * 檢測一個獲取任務失敗的work線程是否可以退出了。
     * 出現下面三種情況,work線程就會死亡。
     * 1、如果pool的狀態爲STOP或TERMINATED
     * 2、隊列爲空
     * 3、允許回收核心線程並且池中的線程數大於1和corePoolSize的最大值
     */
    private boolean workerCanExit() {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        boolean canExit;
        try {
            canExit = runState >= STOP ||
                workQueue.isEmpty() ||
                (allowCoreThreadTimeOut &&
                 poolSize > Math.max(1, corePoolSize));
        } finally {
            mainLock.unlock();
        }
        return canExit;
    }
複製代碼

workerDone(Worker w)

複製代碼
    void workerDone(Worker w) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            completedTaskCount += w.completedTasks;
            workers.remove(w);//從workers集合中刪除該線程
            if (--poolSize == 0)//如果池中的線程數爲0
                tryTerminate();
        } finally {
            mainLock.unlock();
        }
    }
複製代碼

 

3.2、ensureQueuedTaskHandled(Runnable command)

複製代碼
    /**
     * 在一個task入隊之後重新檢查state。
     * 當一個task入隊後,pool的state發生了變化,該方法就會被調用。
     * 如果一個task入隊的同時,shutdownNow方法發生了調用,該方法就必須從隊列中移除並回絕
     * 否則該方法會保證至少有一個線程來處理入隊的task
     */
    private void ensureQueuedTaskHandled(Runnable command) {
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        boolean reject = false;
        Thread t = null;
        try {
            int state = runState;
            if (state != RUNNING && workQueue.remove(command))
                reject = true;
            else if (state < STOP &&
                     poolSize < Math.max(corePoolSize, 1) &&
                     !workQueue.isEmpty())
                t = addThread(null);
        } finally {
            mainLock.unlock();
        }
        if (reject)
            reject(command);
    }
複製代碼

 

3.3、addIfUnderMaximumPoolSize(Runnable firstTask)

複製代碼
    private boolean addIfUnderMaximumPoolSize(Runnable firstTask) {
        Thread t = null;
        final ReentrantLock mainLock = this.mainLock;
        mainLock.lock();
        try {
            if (poolSize < maximumPoolSize && runState == RUNNING)
                t = addThread(firstTask);
        } finally {
            mainLock.unlock();
        }
        return t != null;
    }
複製代碼

說明:該方法的其他方法與addIfUnderCorePoolSize(Runnable firstTask)一樣。

 

3.4、reject(Runnable command)

    void reject(Runnable command) {
        handler.rejectedExecution(command, this);
    }
複製代碼
    public static class AbortPolicy implements RejectedExecutionHandler {
        
        public AbortPolicy() { }
        /** 直接拋異常 */
        public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
            throw new RejectedExecutionException();
        }
    }
複製代碼

發佈了58 篇原創文章 · 獲贊 32 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章