1. 程式人生 > >ThreadPoolExecutor源碼分析(一)

ThreadPoolExecutor源碼分析(一)

策略 n) erro ava 移除 異常 rmi break exec

一、前言

閑來無事,博主有重新翻看了一下jdk1.8版的ThreadPoolExecutor源碼,看後寫此筆記,畫個圈圈,做個記錄,這段源碼,我看過,到處一遊,嘻嘻~~

二、ThreadPoolExecutor數據結構

在ThreadPoolExecutor的內部,主要由BlockingQueue和AbstractQueuedSynchronizer對其提供支持。在鎖框架中,AbstractQueuedSynchronizer抽象類可以毫不誇張的說,占據著核心地位,它提供了一個基於FIFO隊列,可以用於構建鎖或者其他相關同步裝置的基礎框架。

三、ThreadPoolExecutor源碼分析

類的結構圖:

技術分享圖片

通過查看ThreadPoolExecutor源碼的構造函數,corePoolSize(核心線程數),maximumPoolSize(最大線程數),keepAliveTime(當線程池中線程數目>核心線程數,空閑的線程等待任務,即Runnable的時間,超過該時間,該空閑線程將被終止),workQueue(阻塞隊列,當線程池線程數>核心線程數時,新來的Runnable任務將放到阻塞隊列中,待 Worker獲取執行),threadFactory(線程工廠類,創建新的Thread),RejectedExecutionHandler線程拒絕策略,默認是AbortPolicy(拋出RejectedExecutionException異常)

前提:

線程池的五種狀態:

RUNNING(線程池正常運行),SHOUDOWN(不接收提交的新Runnable任務,會接著處理阻塞隊列裏面的任務),STOP(不接收提交的新Runnable任務,不處理阻塞隊列裏面的任務,中斷正在處理的任務)

TIDYING(所有的線程都被終止,執行自定義的鉤子方法terminated()

),TERMINATED(線程池終止,終極狀態)

接下來,來看線程池提交方法execute(註:submit方法內部也是會調用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);
    }

  1:若當前線程池線程數目 < 核心線程數目 ,直接把Runable任務加入新建的Worker中,並啟動任務。

2:若線程池正常(ctl == RUNNING),直接創建一個新的Woker,即開啟一個新的線程執行Runnable任務。

3: 若線程池線程數目>核心線程數目,並且阻塞隊列未滿,添加到阻塞隊列中,並進行二次判斷當前線程池是否還是正常運行的(ctl==Runnable)

becasuse: 若在此時調用了shutdown () or shoutdownNow()方法的話,說明線程池已經發出終止請求,不應該在把新的任務添加到阻塞隊列中,並且執行拒絕策略。

4: 線程池允許的最大線程數目>若線程池線程數目>核心線程數目 & 阻塞隊列已滿, 新建Woker線程執行Runnable任務。

5: 若線程池線程數目>=線程池允許的最大線程數目,對於新提交的任務執行拒絕策略。

在這一連串的邏輯判斷中,需要註意一下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()))
                return false;

            for (;;) {
                int wc = workerCountOf(c);
                if (wc >= CAPACITY ||
                    wc >= (core ? corePoolSize : maximumPoolSize))
                    return false;
                if (compareAndIncrementWorkerCount(c))
                    break retry;
                c = ctl.get();  // Re-read ctl
                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 {
            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) {
                    t.start();
                    workerStarted = true;
                }
            }
        } finally {
            if (! workerStarted)
                addWorkerFailed(w);
        }
        return workerStarted;
    }

  該方法先判斷線程池狀態是否發生改變(是否還是RUNNING狀態),若不是直接返回false,判斷線程池當前線程數目是否大於核心線程數目,超過返回false.

否則新建woker線程,並把新建線程加入到wokers的集合中,啟動新建的線程。

啟動新建線程會調用Worker實例裏面的run方法,run方法中調了runWorker方法,研究一下這個方法:

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();
      
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() &&
                      runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    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 {
                        afterExecute(task, thrown);
                    }
                } finally {
                    task = null;
                    w.completedTasks++;
                    w.unlock();
                }
            }
            completedAbruptly = false;
        } finally {
            processWorkerExit(w, completedAbruptly);
        }
    }

  如果傳入的任務不為空,則先執行傳入的任務,執行完成後去阻塞隊列中獲取任務執行。

若傳入的任務為空,則直接去阻塞隊列裏面獲取任務執行。

若阻塞隊列為空,則runWorker 執行finally代碼塊。線程池工作線程數目-1,把這個woker從wokers集合移除,並且中斷改woker線程。

, 今天就更新到這,下次持續更新ing..................

ThreadPoolExecutor源碼分析(一)