【併發編程】Executor線程池框架-圖文源碼詳解

目錄

0 框架類圖

1. Executors工具類

2 ThreadPoolExecutor 

2.1 API常用方法

2.1.1 構造方法

2.1.2 核心方法execute(Runnable r)

2.1.3 addWorker創建工作線程

2.2 組件解析

2.2.1 worker

2.2.2 ThreadFactory

2.2.3 BlockingQueue


0 框架類圖

在這裏插入圖片描述

常用的Executors類是工具類,靜態工廠方法(簡單工廠模式),實際生產ThreadPoolExecutor。

ThreadPoolExecutor是核心實現類,下面來詳細介紹

1. Executors工具類

API如下,常用幾種種靜態工廠方法newFixedThreadPool固定大小、newSingleThreadExecutor單線程、newCachedThreadPoolnewScheduledThreadPool固定時延(定時任務),實際生產出來的都是ThreadPoolExecutor

ThreadPoolExecutor

構造參數

newFixedThreadPool(n) newSingleThreadExecutor() newCachedThreadPool() newScheduledThreadPool(n)
corePoolSize n(方法參數) 1 0 n
maximumPoolSize n 1 Integer.MAX_VALUE Integer.MAX_VALUE
keepAliveTime 0 0 60 0
unit MILLISECONDS毫秒 MILLISECONDS毫秒 SECONDS秒 MILLISECONDS毫秒
workQueue LinkedBlockingQueue LinkedBlockingQueue SynchronousQueue DelayedWorkQueue
public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>());
}
...
public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS, new DelayedWorkQueue());
}

2 ThreadPoolExecutor 

2.1 API常用方法

2.1.1 構造方法

有4個構造方法,最常用第一個,帶5個參數,參數接受稍後詳解,

剩餘的就是多指明線程工廠和拒絕策略,線程工廠用與創建線程,而拒絕策略就是在提交任務數 > maxPoolSize+queueSize時拒絕線程。

第一個構造方法如下:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue);

ThreadPoolExecutor 是Executor的基本實現,構造參數如下,通過這些參數可以控制其大小等

參數 含義 圖解
corePoolSize 線程池基本大小

maximumPoolSize 線程池最大大小

keepAliveTime

線程存活時間,

空間時間**>keepAliveTime

標記爲可回收

unit

時間單位,

枚舉可設置爲秒、毫秒等

 
workQueue 工作隊列類型

2.1.2 核心方法execute(Runnable r)

提交任務到線程池

2.1.3 addWorker創建工作線程

前置會判斷當前的線程數量,此處省略了,當符合size條件符合(如上圖展示),就會

new Worker實例(會使用線程工廠threadFactory創建一個以當前worker爲Runnable參數的新線程),

然後一些狀態判斷,並加入到線程池ThreadPoolExecutor的workers集合,

最後啓動線程start,調度後就能執行這個Worker的run方法。具體請見下面Worker章節~

2.2 組件解析

主要包含Worker、ThreadFactory、BlockingQueue

2.2.1 worker

就是工作線程,實現了Runnable,並持有Runnable

構造方法

Worker(Runnable firstTask) {
    setState(-1); // inhibit interrupts until runWorker
    this.firstTask = firstTask;
    this.thread = getThreadFactory().newThread(this);
}

run方法

主要是在while循環體中一直從任務隊列中獲取Runnable任務,直接調用其run方法,所以並不是提交多少次就會生產多少線程去執行任務的,工作線程是複用的,工作線程的run方法中循環調用任務的run方法而已。(命令模式)

    final void runWorker(Worker w) {
        Thread wt = Thread.currentThread();
        Runnable task = w.firstTask;
        w.firstTask = null;
        w.unlock(); // 允許中斷
        boolean completedAbruptly = true;
        try {
            while (task != null || (task = getTask()) != null) { // 首次任務||從隊列獲取任務workQueue.take();
                w.lock();
                // 如果線程池被置爲stoping,中斷線程 否則保證不中斷
                if ((runStateAtLeast(ctl.get(), STOP) ||
                     (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
                    !wt.isInterrupted())
                    wt.interrupt();
                try {
                    beforeExecute(wt, task);// 空實現
                    try {
                        task.run(); // 執行任務!!!
                    } 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); // 空閒且非core則銷燬worker
        }
    }

2.2.2 ThreadFactory

ThreadFactory是個接口,顧名思義就是用於生產線程的工廠,(簡單工廠模式),我們通常不指定這個參數,所以會選用默認的實現。

默認實現DefaultThreadFactory是Executors的靜態內部類,主要生產線程的方法非常簡單,如下

public Thread newThread(Runnable r) {
    Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(),0);
    if (t.isDaemon())
        t.setDaemon(false); //非守護線程
    if (t.getPriority() != Thread.NORM_PRIORITY)
        t.setPriority(Thread.NORM_PRIORITY); //普通優先級
    return t;
}

2.2.3 BlockingQueue

通常的生產者/消費者模型會選擇使用BlockingQueue,主要特性就是在空時取會阻塞,滿時offer會阻塞,家族如下,

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