1.ThreadPoolExcuter原理說明 首先我們要知道為什麼要使用ThreadPoolExcuter,具體可以看看文檔中的說明: 線程池可以解決兩個不同問題:由於減少了每個任務的調用開銷,在執行大量的非同步任務時,它通常能夠提供更好的性能,並且還可以提供綁定和管理資源(包括執行集合任務時使用的 ...
1.ThreadPoolExcuter原理說明
首先我們要知道為什麼要使用ThreadPoolExcuter,具體可以看看文檔中的說明:
線程池可以解決兩個不同問題:由於減少了每個任務的調用開銷,在執行大量的非同步任務時,它通常能夠提供更好的性能,並且還可以提供綁定和管理資源(包括執行集合任務時使用的線程)的方法。每個 ThreadPoolExecutor還維護著一些基本的統計數據,如完成的任務數。
線程池做的其實可以看得很簡單,其實就是把你提交的任務(task)進行調度管理運行,但這個調度的過程以及其中的狀態控制是比較複雜的。
2.初始化參數介紹
可以直接看最完整的ThreadPoolExcuter的初始化函數:
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) { ... }
逐個介紹如下:
corePoolSize:核心線程數,在ThreadPoolExcutor中有一個與它相關的配置:allowCoreThreadTimeOut(預設為false),當allowCoreThreadTimeOut為false時,核心線程會一直存活,哪怕是一直空閑著。而當allowCoreThreadTimeOut為true時核心線程空閑時間超過keepAliveTime時會被回收。
maximumPoolSize:最大線程數,線程池能容納的最大線程數,當線程池中的線程達到最大時,此時添加任務將會採用拒絕策略,預設的拒絕策略是拋出一個運行時錯誤(RejectedExecutionException)。值得一提的是,當初始化時用的工作隊列為LinkedBlockingDeque時,這個值將無效。
keepAliveTime:存活時間,當非核心空閑超過這個時間將被回收,同時空閑核心線程是否回收受allowCoreThreadTimeOut影響。
unit:keepAliveTime的單位。
workQueue:任務隊列,常用有三種隊列,即SynchronousQueue,LinkedBlockingDeque(無界隊列),ArrayBlockingQueue(有界隊列)。
threadFactory:線程工廠,ThreadFactory是一個介面,用來創建worker。通過線程工廠可以對線程的一些屬性進行定製。預設直接新建線程。
RejectedExecutionHandler:也是一個介面,只有一個方法,當線程池中的資源已經全部使用,添加新線程被拒絕時,會調用RejectedExecutionHandler的rejectedExecution法。
預設是拋出一個運行時異常。
這裡需要做一個額外說明,在ThreadPoolExcuter中,worker和task是有區別的,task是用戶提交的任務,而worker則是用來執行task的線程。在初始化參數中,corePoolSize和maximumPoolSize都是針對worker的,而workQueue是用來存放task的。
3.ctl介紹以及運行狀態說明
首先需要介紹線程池有五種運行狀態:
RUNNING(狀態值-1): 接收新任務並處理隊列中的任務
SHUTDOWN(狀態值0): 不接收新任務但會處理隊列中的任務。
STOP(狀態值1): 不接收新任務,不處理隊列中的任務,並中斷正在處理的任務
TIDYING(狀態值2): 所有任務已終止,workerCount為0,處於TIDYING狀態的線程將調用鉤子方法terminated()。
TERMINATED(狀態值3): terminated()方法完成。
然後我們可以看看ThreadPoolExcuter中的ctl這個變數。
ctl是ThreadPoolExcuter中比較有意思的一個實現,它是一個AtomicInteger,這裡不對AtomicInteger多做討論,只要知道可以把它看成有原子性的Integer就夠了,其實它具有原子性的原理是使用了CAS的技術,這是一種樂觀鎖的具體實現。
ThreadPoolExcuter是將兩個內部值打包成一個值,即將workerCount和runState(運行狀態)這兩個值打包在一個ctl中,因為runState有5個值,需要3位,所以有3位表示
runState,而其他29位表示為workerCount。
而運行時要獲取其他數據時,只需要對ctl進行拆包即可。具體這部分代碼如下:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); private static final int COUNT_BITS = Integer.SIZE - 3; private static final int CAPACITY = (1 << COUNT_BITS) - 1; // runState is stored in the high-order bits private static final int RUNNING = -1 << COUNT_BITS; private static final int SHUTDOWN = 0 << COUNT_BITS; private static final int STOP = 1 << COUNT_BITS; private static final int TIDYING = 2 << COUNT_BITS; private static final int TERMINATED = 3 << COUNT_BITS; // Packing and unpacking ctl
//拆包ctl,分別獲取runState和WorkerCount 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; }
總結:本篇初步介紹了ThreadPoolExcuter的基本原理,解決了什麼問題。而後說明瞭ThreadPoolExcuter中的初始化參數,對其中的各個參數做初步介紹。再之後介紹ctl變數的作用。