這是我參與更文挑戰的第8天,活動詳情查看:更文挑戰數組
線程池就是管理線程的池子,首先建立一些線程,它們的集合稱爲線程池。使用線程池能夠很好地提升性能,線程池在系統啓動時即建立大量空閒的線程,程序將一個任務傳給線程池,線程池就會啓動一條線程來執行這個任務,執行結束之後,該線程並不會死亡,而是再次返回線程池中成爲空閒狀態,等待執行下一個任務。緩存
線程池的優點 經過重用已存在的線程,下降線程建立和銷燬線程形成的開銷, 提升系統響應速度,當有任務到達時,直接從線程池中取線程,經過複用已存在的線程,無需等待便能當即執行; 提升線程可管理性。由於線程如果無限制的建立,不只會消耗系統資源,還會下降系統穩定性。(內存佔用過多而產生OOM,而且會形成cpu過分切換)markdown
不管是建立何種類型線程池(FixedThreadPool、CachedThreadPool…),均會調用ThreadPoolExecutor構造函數。 newFixedThreadPool (固定數目線程的線程池) newCachedThreadPool(可緩存線程的線程池) newSingleThreadExecutor(單線程的線程池) newScheduledThreadPool(定時及週期執行的線程池)less
public ThreadPoolExecutor(
int corePoolSize, // 線程池長期維持的線程數,即便線程處於Idle狀態,也不會回收。
int maximumPoolSize, // 線程數的上限
long keepAliveTime, TimeUnit unit, // 超過corePoolSize的線程的idle時長,
// 超過這個時間,多餘的線程會被回收。
BlockingQueue<Runnable> workQueue, // 任務的排隊隊列
ThreadFactory threadFactory, // 新線程的產生方式
RejectedExecutionHandler handler) // 拒絕策略
複製代碼
corePoolSize:the number of threads to keep in the pool, even if they are idle, unless {@code allowCoreThreadTimeOut} is set (核心線程數大小:無論它們建立之後是否是空閒的。線程池須要保持 corePoolSize 數量的線程,除非設置了 allowCoreThreadTimeOut。)svn
maximumPoolSize:the maximum number of threads to allow in the pool。(最大線程數:線程池中最多容許建立 maximumPoolSize 個線程。)函數
keepAliveTime:when the number of threads is greater than the core, this is the maximum time that excess idle threads will wait for new tasks before terminating。(存活時間:若是通過 keepAliveTime 時間後,超過核心線程數的線程尚未接受到新的任務,那就回收。)post
unit:the time unit for the {@code keepAliveTime} argument (keepAliveTime 的時間單位。)性能
workQueue:the queue to use for holding tasks before they are executed. This queue will hold only the {@code Runnable} tasks submitted by the {@code execute} method。(存放待執行任務的隊列:當提交的任務數超過核心線程數大小後,再提交的任務就存放在這裏。它僅僅用來存放被 execute 方法提交的 Runnable 任務。因此這裏就不要翻譯爲工做隊列了,好嗎?不要本身給本身挖坑。)flex
threadFactory:the factory to use when the executor creates a new thread。(線程工程:用來建立線程工廠。好比這裏面能夠自定義線程名稱,當進行虛擬機棧分析時,看着名字就知道這個線程是哪裏來的,不會懵逼。)this
handler :the handler to use when execution is blocked because the thread bounds and queue capacities are reached。(拒絕策略:當隊列裏面放滿了任務、最大線程數的線程都在工做時,這時繼續提交的任務線程池就處理不了,應該執行怎麼樣的拒絕策略。)
提交一個任務,線程池裏存活的核心線程數小於線程數corePoolSize時,線程池會建立一個核心線程去處理提交的任務。
若是線程池核心線程數已滿,即線程數已經等於corePoolSize,一個新提交的任務,會被放進任務隊列workQueue排隊等待執行。
當線程池裏面存活的線程數已經等於corePoolSize了,而且任務隊列workQueue也滿,判斷線程數是否達到maximumPoolSize,即最大線程數是否已滿,若是沒到達,建立一個非核心線程執行提交的任務。
若是當前的線程數達到了maximumPoolSize,還有新的任務過來的話,直接採用拒絕策略處理。
線程池拒絕策略分爲一下幾種: AbortPolicy:直接拋出RejectedExecutionException,默認策略。
DiscardPolicy: 什麼也不作,直接丟棄任務。
DiscardOldestPolicy:拋棄下一個將要被執行的任務(丟棄執行隊列中最老的任務,嘗試爲當前提交的任務騰出位置)。
CallerRunsPolicy:主線程中執行任務(由提交任務者執行這個任務)。
幾種典型的工做隊列 ArrayBlockingQueue:使用數組實現的有界阻塞隊列,特性先進先出。
LinkedBlockingQueue:LinkedBlockingQueue(可設置容量隊列)基於鏈表結構的阻塞隊列,按FIFO排序任務,容量能夠選擇進行設置,不設置的話,將是一個無邊界的阻塞隊列,最大長度爲Integer.MAX_VALUE,吞吐量一般要高於ArrayBlockingQuene;newFixedThreadPool線程池使用了這個隊列;
PriorityBlockingQueue:使用平衡二叉樹堆,實現的具備優先級的無界阻塞隊列
DelayQueue:DelayQueue(延遲隊列)是一個任務定時週期的延遲執行的隊列。根據指定的執行時間從小到大排序,不然根據插入到隊列的前後排序; newScheduledThreadPool線程池使用了這個隊列;
SynchronousQueue:一個不存儲元素的阻塞隊列,每一個插入操做,必須等到另外一個線程調用移除操做,不然插入操做一直處於阻塞狀態。吞吐量一般要高於LinkedBlockingQuene,newCachedThreadPool線程池使用了這個隊列;
LinkedTransferQueue: 一個由鏈表結構組成的無界阻塞隊列。 相對於其餘阻塞隊列LinkedTransferQueue多了tryTransfer和transfer方法。
LinkedBlockingDeque: 一個由鏈表結構組成的雙向阻塞隊列。 是一個由鏈表結構組成的雙向阻塞隊列
SingleThreadExecutor: public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue())); }
建立單個線程。它適用於須要保證順序地執行各個任務;而且在任意時間點,不會有多個線程是活動的應用場景。
SingleThreadExecutor的corePoolSize和maximumPoolSize被設置爲1,每次只能有一個線程存活。使用無界隊列LinkedBlockingQueue(先進先出原則,因此保證了任務的按順序逐一進行)做爲線程池的工做隊列。
當線程池中沒有線程時,會建立一個新線程來執行任務。
當前線程池中有一個線程後,將新任務加入LinkedBlockingQueue
線程執行完第一個任務後,會在一個無限循環中反覆從LinkedBlockingQueue 獲取任務來執行。 keepAliveTime爲0
使用場景:適用於串行執行任務的場景,一個任務一個任務地執行;
FixedThreadPool:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
複製代碼
特色: 核心線程數和最大線程數大小同樣 keepAliveTime爲0L,表明多餘的線程馬上終止 阻塞隊列爲無界隊列LinkedBlockingQueue
FixedThreadPool是一種線程數量固定的線程池,當線程處於空閒狀態時,他們並不會被回收,除非線程池被關閉。當全部的線程都處於活動狀態時,新的任務都會處於等待狀態,直到有線程空閒出來。
注意:使用無界隊列的線程池會致使內存飆升,由於newFixedThreadPool使用了無界的阻塞隊列LinkedBlockingQueue,若是線程獲取一個任務後,任務的執行時間比較長,會致使隊列的任務越積越多,致使機器內存使用不停飆升, 最終致使OOM;
使用場景:適用於處理CPU密集型的任務,確保CPU在長期被工做線程使用的狀況下,儘量的少的分配線程,即適用執行長期的任務。
CachedThreadPool:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
複製代碼
特色:
核心線程數爲0 所有都是非核心線程,最大線程數爲Integer.MAX_VALUE 阻塞隊列是SynchronousQueue(最多隻能存在一個元素,有新的任務則阻塞等待) 非核心線程空閒存活時間爲60秒
使用場景:執行大量短生命週期任務。由於maximumPoolSize是無界的,因此提交任務的速度 > 線程池中線程處理任務的速度就要不斷建立新線程;每次提交任務,都會當即有線程去處理,所以CachedThreadPool適用於處理大量、耗時少的任務。
ScheduledThreadPool:
線程總數閾值爲Integer.MAX_VALUE,工做隊列使用DelayedWorkQueue,
非核心線程存活時間爲0,因此線程池僅僅包含固定數目的核心線程。
兩種方式提交任務:
scheduleAtFixedRate: 按照固定速率週期執行
scheduleWithFixedDelay:上個任務延遲固定時間後執行
使用場景:週期性執行任務,而且須要限制線程數量的場景