線程池執行流程及原理解析

線程模型

用戶線程(UTL):由應用去管理線程,不需要用戶態-內核態切換。

內核線程(KTL):創建線程在任務管理器中可見,java創建的線程由操作系統管理,操作系統對應一個內核空間線程,線程和內核線程一一對應。

private native void start0();

java的線程是KTL內核線程模型。關鍵代碼,Thread類中創建線程,是由本地方法庫中的start0方法創建線程。

線程狀態:

private final AtomicInteger ctl = new AtomicInteger(RUNNING);
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY   = (1 << COUNT_BITS) - 1; // 2^29

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS; // 111
private static final int SHUTDOWN   =  0 << COUNT_BITS; // 000
private static final int STOP       =  1 << COUNT_BITS; // 001
private static final int TIDYING    =  2 << COUNT_BITS; // 010
private static final int TERMINATED =  3 << COUNT_BITS; // 011

private static int runStateOf(int c)     { return c & ~CAPACITY; } // 獲取當前狀態
private static int workerCountOf(int c)  { return c & CAPACITY; } // 活動線程的數量
private static int ctlOf(int rs, int wc) { return rs | wc; }

// 運算結果(高3位爲狀態、低29位爲數量)
COUNT_BITS:29
CAPACITY  :000 11111111111111111111111111111
RUNNING   :111 00000000000000000000000000000
SHUTDOWN  :000 00000000000000000000000000000
STOP      :001 00000000000000000000000000000
TIDYING   :010 00000000000000000000000000000
TERMINATED:011 00000000000000000000000000000

ctl:記錄活動線程的數量(低29位)、線程池的狀態(高3位)【Integer.SIZE共32位】

CAPACITY=0 :初始容量

COUNT_BITS:29 =(Integer.SIZE=32)-3,

RUNNING(111):接受新任務、可以處理已添加的任務。

SHUTDOWN(000):不接受新任務、可以處理已添加的任務。

STOP(001):不接受新任務、不處理已添加的任務、並且中斷正在處理的任務。

TIDYING(010):所有的任務已經終止,ctl數=0。

TERMINATED(011):線程池終止。

構造函數解析

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.acc = System.getSecurityManager() == null ?
        null :
    AccessController.getContext();
    this.corePoolSize = corePoolSize;
    this.maximumPoolSize = maximumPoolSize;
    this.workQueue = workQueue;
    this.keepAliveTime = unit.toNanos(keepAliveTime);
    this.threadFactory = threadFactory;
    this.handler = handler;
}
  • acc : 獲取調用上下文
  • corePoolSize: 核心線程數量,規定線程池有幾個線程(worker)在運行。
  • maximumPoolSize: 最大的線程數量。當workQueue滿了,不能添加任務的時候,這個參數纔會生效。規定線程池中最多有多少個線程(worker)在執行
  • workQueue:存放任務的隊列。
  • unit: 生存時間對於的單位
  • keepAliveTime:超出corePoolSize大小的那些線程的生存時間,這些線程如果長時間沒有執行任務並且超過了該keepAliveTime設定的時間,就會消亡。
  • threadFactory: 創建線程的工廠,在這個地方可以統一處理創建的線程的屬性。
  • handler:當workQueue已經滿了,並且線程池線程數已經達到maximumPoolSize,將執行拒絕策略。

線程池執行流程

// 執行任務方法
public void execute(Runnable command) {
	// 1、小於核心線程數,直接創建線程執行任務addWorker(command, true)
    int c = ctl.get();
    if (workerCountOf(c) < corePoolSize) {
        if (addWorker(command, true))
            return;
        c = ctl.get();
    }
    // 2、大於核心線程數,嘗試加入隊列,進行雙重檢測線程池運行狀態
    // 創建非核心線程執行任務addWorker(null, false)
    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(command, false)在自旋時狀態檢測返回false,未創建Worker對象
    // 則執行拒絕策略
    else if (!addWorker(command, false))
        reject(command);
}
// 添加worker對象到workers集合中
private boolean addWorker(Runnable firstTask, boolean core) {
    // 
    retry:
    for (;;) {
        int c = ctl.get();
        int rs = runStateOf(c);
		// 1、檢測線程池的狀態,如果關閉了則不再添加worker,直接返回false
        if (rs >= SHUTDOWN &&
            ! (rs == SHUTDOWN &&
               firstTask == null &&
               ! workQueue.isEmpty()))
            return false;

        // 2、自旋的方式對活動的線程數workercount+1
        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;
        }
    }

    boolean workerStarted = false;
    boolean workerAdded = false;
    Worker w = null;
    try {
        // 3、封裝worker對象,內部創建了新的線程,w.thread即可獲取該線程
        w = new Worker(firstTask);
        final Thread t = w.thread;
        if (t != null) {
            // 4、通過線程池的重入鎖機制,將worker加入workers集合中,等待workers執行。
            final ReentrantLock mainLock = this.mainLock;
            mainLock.lock();
            try {
                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();
            }
            // 5、加入成功後,調用該線程執行。
            if (workerAdded) {
                t.start();
                workerStarted = true;
            }
        }
    } finally {
        // 加入線程池失敗,則內部通過自旋的方式,將活動線程數workerCount-1
        if (! workerStarted)
            addWorkerFailed(w);
    }
    return workerStarted;
}
Worker(Runnable firstTask) {
    setState(-1); 
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);	// 1、此處將worker對象本身加入線程
}
public void run() {	// 2、由於worker對象實現Runnable,由1處的thread執行start時,會調用該方法
    runWorker(this);	// 3、該runWorker方法爲線程池的runWorker方法。
}

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
	// 4、此處只留下了關鍵代碼,如果firstTask==null,則通過getTask方法從隊列中獲取任務。
    while (task != null || (task = getTask()) != null) {
        // 5、執行任務
        task.run();
    }
}

線程集合:HashSet:workers :不斷的從workQueue隊列中獲取線程,執行任務

阻塞隊列:BlockingQueue:workQueue:存放線程任務的隊列,FIFO一端入隊一端出隊

流程原理:

1、用戶向線程池中提交線程任務,執行execute方法。

2、如果當前線程池中的線程數量workerCount小於核心線程數corepoolsize

​ 2.1、通過自旋的方式對workerCount數量做CAS進行+1,如果當前活動線程>corepoolsize或者maxinumpoolsize,則自旋失敗,返回false,如果成功,則開始封裝Worker對象

​ 2.2、通過線程任務封裝Worker對象時,先獲取線程池的重入鎖,獲取鎖後判斷當前線程池的狀態,如果爲001、010、011狀態,則操作失敗,會對workerCount數量CAS做-1,同時停止線程池,返回false。

​ 2.3、線程池將該線程封裝成Worker對象,添加到workers執行。

3、如果當前線程池中的線程數量workerCount達到了corepoolsize,則將任務加入workQueue隊列中。

4、如果隊列已經滿,但未達到maxinumpoolsize數量,新建(非核心)線程執行任務。

​ 4.1、由addWorker(command, false),添加的firstTask爲null,所以封裝的Worker對象的firstTask爲null,

​ 4.2、由Worker對象執行線程,由於firstTask==null,所以不斷循環的從workQueue隊列中獲取任務步驟3加入的任務執行。

​ 4.3、執行完成後對該任務標記completedTaskCount已完成數量。同時移除該任務。

5、如果隊列已經滿,總線程數達到了maxinumpoolsize數量,會由RejectedExecutionHandler執行拒絕策略。
在這裏插入圖片描述

默認線程池:

newFixedThreadPool:指定線程的線程池,核心數=最大數,不會釋放線程

newCachedThreadPool:可緩存60秒線程的線程池,核心數=0,最大數=Integer.MAX會自動釋放線程

newSingleThreadExecutor:只有一個線程,核心數=最大數=1,可以保證線程的任務順序執行

newScheduledThreadPool:可以指定時間、週期性執行提交的任務線程

默認任務隊列:

1、ArrayBlockingQueue:基於數組結構的有界阻塞隊列,按FIFO排序任務;
2、LinkedBlockingQuene:基於鏈表結構的阻塞隊列,按FIFO排序任務,吞吐量通常要高於ArrayBlockingQuene;
3、SynchronousQuene:一個不存儲元素的阻塞隊列,每個插入操作必須等到另一個線程調用移除操作,否則插入操作一直處於阻塞狀態,吞吐量通常要高於LinkedBlockingQuene;
4、PriorityBlockingQuene:具有優先級的無界阻塞隊列;

默認拒絕策略:

1、AbortPolicy:直接拋出異常,默認策略;
2、CallerRunsPolicy:用調用者所在的線程來執行任務;
3、DiscardOldestPolicy:丟棄阻塞隊列中靠最前的任務,並執行當前任務;
4、DiscardPolicy:直接丟棄任務;
當然也可以根據應用場景實現RejectedExecutionHandler接口,自定義飽和策略,如記錄日誌或持久化存儲不能處理的任務。

參考資料:

https://blog.csdn.net/u013332124/article/details/79587436

https://www.jianshu.com/p/87bff5cc8d8c

https://www.cnblogs.com/DDiamondd/p/11362164.html

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