執行緒池原理(JDK1.8)

食魚醬發表於2018-08-06

Java中的執行緒池

ThreadPoolExecutor是執行緒池類。對於執行緒池,可以通俗的將它理解為”存放一定數量執行緒的一個執行緒集合。執行緒池允許若個執行緒同時允許,允許同時執行的執行緒數量就是執行緒池的容量;當新增的到執行緒池中的執行緒超過它的容量時,會有一部分執行緒阻塞等待。執行緒池會通過相應的排程策略和拒絕策略,對新增到執行緒池中的執行緒進行管理。

組成(這部分轉自執行緒池原理——skywang12345

// 阻塞佇列
private final BlockingQueue<Runnable> workQueue;

// 互斥鎖
private final ReentrantLock mainLock = new ReentrantLock();

// 執行緒集合。一個Worker對應一個執行緒。
private final HashSet<Worker> workers = new HashSet<Worker>();

// “終止條件”,與“mainLock”繫結。
private final Condition termination = mainLock.newCondition();

// 執行緒池中執行緒數量曾經達到過的最大值。
private int largestPoolSize;

// 已完成任務數量
private long completedTaskCount;

// ThreadFactory物件,用於建立執行緒。
private volatile ThreadFactory threadFactory;

// 拒絕策略的處理控制程式碼。
private volatile RejectedExecutionHandler handler;

// 保持執行緒存活時間。
private volatile long keepAliveTime;

private volatile boolean allowCoreThreadTimeOut;

// 核心池大小
private volatile int corePoolSize;

// 最大池大小
private volatile int maximumPoolSize;

1.workers

workers是HashSet型別,即它是一個Worker集合。而一個Worker對應一個執行緒,也就是說執行緒池通過workers包含了”一個執行緒集合”。當Worker對應的執行緒池啟動時,它會執行執行緒池中的任務;當執行完一個任務後,它會從執行緒池的阻塞佇列中取出一個阻塞的任務來繼續執行。
wokers的作用是,執行緒池通過它實現了”允許多個執行緒同時執行”。

2.workQueue

workQueue是BlockingQueue型別,即它是一個阻塞佇列。當執行緒池中的執行緒數超過它的容量的時候,執行緒會進入阻塞佇列進行阻塞等待。
通過workQueue,執行緒池實現了阻塞功能。

3. mainLock

mainLock是互斥鎖,通過mainLock實現了對執行緒池的互斥訪問。

4. corePoolSize和maximumPoolSize

corePoolSize是”核心池大小”,maximumPoolSize是”最大池大小”。它們的作用是調整”執行緒池中實際執行的執行緒的數量”。
例如,當新任務提交給執行緒池時(通過execute方法)。
– 如果此時,執行緒池中執行的執行緒數量< corePoolSize,則建立新執行緒來處理請求。
– 如果此時,執行緒池中執行的執行緒數量> corePoolSize,但是卻< maximumPoolSize;則僅當阻塞佇列滿時才建立新執行緒。
如果設定的 corePoolSize 和 maximumPoolSize 相同,則建立了固定大小的執行緒池。如果將 maximumPoolSize 設定為基本的無界值(如 Integer.MAX_VALUE),則允許池適應任意數量的併發任務。在大多數情況下,核心池大小和最大池大小的值是在建立執行緒池設定的;但是,也可以使用 setCorePoolSize(int) 和 setMaximumPoolSize(int) 進行動態更改。

5. poolSize

poolSize是當前執行緒池的實際大小,即執行緒池中任務的數量。

6. allowCoreThreadTimeOut和keepAliveTime

allowCoreThreadTimeOut表示是否允許”執行緒在空閒狀態時,仍然能夠存活”;而keepAliveTime是當執行緒池處於空閒狀態的時候,超過keepAliveTime時間之後,空閒的執行緒會被終止。

7. threadFactory

threadFactory是ThreadFactory物件。它是一個執行緒工廠類,”執行緒池通過ThreadFactory建立執行緒”。

8. handler

handler是RejectedExecutionHandler型別。它是”執行緒池拒絕策略”的控制程式碼,也就是說”當某任務新增到執行緒池中,而執行緒池拒絕該任務時,執行緒池會通過handler進行相應的處理”。



原理(原始碼是JDK1.8)

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

     int c = ctl.get();
     /*
         1、判斷當前的工作執行緒是否小於執行緒池裡的核心執行緒,如果滿足,則建立一個新的工作執行緒來執行任務。
         如果不滿足,則進入下個流程。

         注意:此時addWorker的第二個引數為true;
     */ 
     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);
         else if (workerCountOf(recheck) == 0)
             addWorker(null, false);
     }
     //3、嘗試建立執行緒    注意:此時addWorker的第二個引數為false,下面會解釋
     else if (!addWorker(command, false))
         reject(command);
 }

//該方法用於建立執行緒,注意該方法的第二個引數core
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);
                /*
                    當core為false時,下面判斷執行緒池corePoolSize和maximumPoolSize 的差值,如果此時,
                    執行緒池中執行的執行緒數量> corePoolSize,但是卻< maximumPoolSize,則會繼續建立一個
                    新的工作執行緒。
                */
                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;
    }

總結

1、判斷當前的工作執行緒是否小於執行緒池裡的核心執行緒,如果滿足,則建立一個新的工作執行緒來執行任務。不滿足則進入下個流程。

2、執行緒池判斷工作佇列是否已滿,如果工作佇列沒有滿,則將新提交的任務儲存在這個工作佇列裡。如果工作佇列滿了,則進入下個流程。

3、判斷執行緒池corePoolSize和maximumPoolSize 的差值,如果此時,執行緒池中執行的執行緒數量> corePoolSize,但是卻< maximumPoolSize,則建立一個新的工作執行緒來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。

相關文章