Java多線程(二)線程池

前言

這是筆者學習的筆記,分享出來,僅供大家參考
源碼基於jdk1.8

四種線程池

併發三大特性:原子性、可見性、有序性
java保證原子性的類AtomicInteger

corePoolSize 線程池基本大小 阻塞隊列滿了的話 纔會在corePoolSize < maximumPoolSize 下創建新的線程, 如果隊列是無窮大的 那麼maximumPoolSize永遠也用不上,
也就是說優先corePoolSize > 阻塞隊列 > maximumPoolSize, 當阻塞隊列+corePoolSize不夠用時,新加任務就會去創建新的線程,新建線程不能超過maximumPoolSize,maximumPoolSize-corePoolSize就是借用的,如果這部分空閒了,就要根據空閒時間來銷燬線程或複用
那麼執行線程也需要存儲的 HashSet 阻塞隊列用的BlockingQueue

1、Executors.newSigleThreadExecutor()

實例化 ThreadPoolExecutor 核心線程數 1, 最大線程數 1 空閒維持時間 0,阻塞隊列 LinkedBlockingQueue

2、Executors.newFixedThreadPool(nThreads)

實例化 ThreadPoolExecutor 指定線程數量== 核心線程數 ==最大線程數, 空閒維持時間 0,阻塞隊列 LinkedBlockingQueue

3、Executors.newCachedThreadPool()

實例化 ThreadPoolExecutor 核心線程數 0,最大線程數 Integer.MAX_VALUE, 空閒維持時間 60秒,阻塞隊列 SynchronousQueue()

4、Executors.newScheduledThreadPool(corePoolSize)

實例化 ScheduledThreadPoolExecutor(corePoolSize) 指定核心線程數,最大線程數 Integer.MAX_VALUE,空閒維持時間 (java 0, android.jar中的改爲10毫秒),阻塞隊列 DelayedWorkQueue()

自定義線程池 可以直接newThreadPoolExecutor 指定線程數量 核心數 空閒維持時間 阻塞隊列

線程池幾種狀態

  • RUNNING: 接受新任務和處理隊列的任務
  • SHUTDOWN: 不接受新任務,但是處理隊列的任務
  • STOP: 不接受新任務,但是處理隊列的任務,終止進行中的任務
  • TIDYING: 所有任務都已終止,workerCount爲零,轉換爲狀態TIDYING的線程將運行terminated() hook method
  • TERMINATED: terminated() 已執行完成

筆者總結的流程圖

從execute->addWorker->runWorker

線程池類繼承關係:
在這裏插入圖片描述

線程池提交任務
在這裏插入圖片描述

addWorker到線程啓動再到線程複用、線程銷燬
在這裏插入圖片描述

execute執行任務

/**
* 執行任務
*
* @param command 任務
*/
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();
    }

    //如果線程池RUNNING 添加到阻塞隊列,
    if (isRunning(c) && workQueue.offer(command)) {
        int recheck = ctl.get();
        //如果沒有RUNNING 將任務從隊列中移除,移除成功執行拒絕策略
        if (! isRunning(recheck) && remove(command))
            reject(command);
        //RUNNING或者移除失敗,判斷工作線程==0,創建一個非核心線程
        else if (workerCountOf(recheck) == 0)
            addWorker(null, false);
    }
    //線程池沒有掛了或者添加隊列失敗也就是隊列滿了,就會去創建非核心線程
    //創建失敗執行拒絕策略
    else if (!addWorker(command, false))
        reject(command);
}


/**
* 添加Worker
*
* @param firstTask 任務Runnable
* @param core      true 核心, false 非核心
* @return true Worker添加成功並啓動成功,false失敗
*/
private boolean addWorker(Runnable firstTask, boolean core) {
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);

        // Check if queue empty only if necessary.
        // SHUTDOWN狀態不接收新任務
        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 {
        //實例化Worker
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            final ReentrantLock mainLock = this.mainLock;
            //HashSet操作 鎖住先
            mainLock.lock();
            try {
                // Recheck while holding lock.
                // Back out on ThreadFactory failure or if
                // shut down before lock acquired.
                int rs = runStateOf(ctl.get());

                //線程池狀態RUNNING或者SHUTDOWN並且進來的任務是null的 執行添加任務 SHUTDOWN是可以接收新任務的
                if (rs < SHUTDOWN ||
                        (rs == SHUTDOWN && firstTask == null)) {
                    //如果worker的thread已經啓動了拋出異常
                    if (t.isAlive()) // precheck that t is startable
                        throw new IllegalThreadStateException();
                    //workers是HashSet,把worker加入到HashSet
                    workers.add(w);
                    int s = workers.size();
                    if (s > largestPoolSize)
                        largestPoolSize = s;
                    workerAdded = true;
                }
            } finally {
                mainLock.unlock();
            }
            if (workerAdded) {
                //worker已經添加啓動線程
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}

可以看到addWorker裏面實例化了一個Worker對象,這裏很有意思,我們跟進去Worker構造函數瞧瞧

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable {
    ...
    Worker(Runnable firstTask) {
        setState(-1); // inhibit interrupts until runWorker
        this.firstTask = firstTask;
        this.thread = getThreadFactory().newThread(this);
    }
    ...
}

獲取線程工廠創建一個thread,把Worker本身傳進去了,所以addWorker()裏面調用Worker.thread.start()方法會執行到Worker.run()

private final class Worker
    extends AbstractQueuedSynchronizer
    implements Runnable {
    ...
    public void run() {
        runWorker(this);
    }
    ...
}

Worker run()方法執行的是runWorker(Worker)
接下來看看runWorker方法

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 {
        //task==null的時候getTask隊列取任務
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            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);
    }
}

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

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

        // 必要時檢查隊列爲 SHUTDOWN && isEmpty 或者 >=STOP
        if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
            //減少工作線程數量
            decrementWorkerCount();
            //並終止while循環銷燬線程
            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())) {
            //嘗試減少工作線程數量1
            if (compareAndDecrementWorkerCount(c))
                //返回null結束while也就銷燬了線程
                return null;
            continue;
        }

        try {
            Runnable r = timed ?
                    workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
                    workQueue.take();
            //poll 隊列爲空返回null timed==true 工作線程>核心 所以等待keepAliveTime 後再銷燬
            //take 隊列爲空阻塞     timed==false 工作線程<=核心 不需要超時等待 阻塞直到拿到任務,所以線程也是阻塞狀態
            if (r != null)
                return r;
            timedOut = true;
        } catch (InterruptedException retry) {
            timedOut = false;
        }
    }
}


總結

開發路漫長,多看看源碼

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