ThreadPoolExecutor 線程池理論、飽和策略、工作隊列排隊策略


本文鏈接:https://blog.csdn.net/wangmx1993328/article/details/80582803
目錄

本文導讀

線程池簡述

Executor結構

使用線程池的好處

線程池工作原理

線程池飽和策略

AbortPolicy

DiscardPolicy

DiscardOldestPolicy

用戶自定義拒絕策略(最常用)

線程池工作流程圖

工作隊列排隊策略

SynchronousQueue

 LinkedBlockingQueue

ArrayBlockingQueue

本文導讀
本文主要描述Java線程池的理論知識
Java中有幾種方法新建一個線程?
繼承Thread或者實現Runnable
使用更高級的線程池
線程池簡述
線程池是JDK1.5開始引入的,也叫Executor框架,或是Java並發框架
線程池相關的API在java.util.concurrent包中,常用到以下幾個類和接口:
java.util.concurrent.Executor:一個只包含一個方法的接口,它的抽象含義是:用來執行一個Runnable任務的執行器
java.util.concurrent.ExecutorService:繼承了Executor接口的接口,增加了很多對於任務和執行器的生命周期進行管理的方法
java.util.concurrent.ThreadFactory:一個生成新線程的接口。用戶可以通過實現這個接口管理對線程池中生成線程的邏輯
java.util.concurrent.Executors:創建並返回其余各個實例的類,提供了很多不同的生成執行器的實用方法,比如基於線程池的執行器的實現。
java.util.concurrent.ThreadPoolExecutor:這個類維護了一個線程池,對於提交到此Executor中的任務,它不是創建新的線程而是使用池內的線程進行執行,對於數量巨大但執行時間很短的任務,可以顯著地減少對於任務執行的開銷。
Executor結構
executor結構主要包括任務、任務的執行和異步結果的計算。
任務:包括被執行任務需要實現的接口,如Runnable接口或Callable接口
任務的執行:包括任務執行機制的核心接口Executor,以及繼承自Executor的ExecutorService接口。Executor框架有兩個關鍵類實現了ExecutorService接口(ThreadPoolExecutor和ScheduledThreadPoolExecutor)
異步計算的結果:包括接口Future和實現Future接口的FutureTask類


使用線程池的好處
降低資源消耗:可以重復利用已創建的線程降低線程創建和銷毀造成的消耗。
提高響應速度:當任務到達時,任務可以不需要等到線程創建就能立即執行。
提高線程的可管理性:線程是稀缺資源,如果無限制地創建,不僅會消耗系統資源,還會降低系統的穩定性,使用線程池可以進行統一分配、調優和監控
線程池工作原理
當一個新的任務提交到線程池之后,線程池處理過程如下:
線程池判斷核心線程池里的線程是否已滿。未滿時,則創建一個新的工作線程來執行任務。如果核心線程池里的線程已滿,則執行第二步。
線程池判斷工作隊列是否已經滿。如果工作隊列沒有滿,則將新提交的任務存儲在這個工作隊列里等待執行。如果工作隊列滿了,則執行第三步。
線程池判斷線程池(核心線程池外的線程池部分)的線程是否都處於工作狀態。如果沒有,則創建一個新的工作線程來執行任務。如果已經滿了,則交給飽和策略來處理這個任務。
線程池飽和策略
常用的飽和策略如下:
它們是ThreadPoolExecutor類中的內部類,可以直接調用


AbortPolicy
Java線程池默認的阻塞策略,即不執行此新任務,而且直接拋出一個運行時異常,切記ThreadPoolExecutor.execute需要try catch,否則程序會直接退出。
DiscardPolicy
直接拋棄,新任務不執行,空方法
DiscardOldestPolicy
從隊列里面拋棄head的一個任務,並再次execute 此task。
用戶自定義拒絕策略(最常用)
實現RejectedExecutionHandler,並自己定義策略模式
線程池工作流程圖
以ThreadPoolExecutor為例展示線程池的工作流程

 


如果當前運行的線程少於corePoolSize(核心線程數),則創建新線程來執行任務(注意,執行這一步驟需要獲取全局鎖)。
如果運行的線程等於或多於corePoolSize,則將任務加入BlockingQueue(阻塞隊列/任務隊列)。
如果無法將任務加入BlockingQueue(隊列已滿),則在非corePool中創建新的線程來處理任務(注意,執行這一步驟需要獲取全局鎖)。
如果創建新線程將使當前運行的線程超出maximumPoolSize,任務將被拒絕,並執行線程飽和策略,如:RejectedExecutionHandler.rejectedExecution()方法。
ThreadPoolExecutor采取上述步驟的總體設計思路,是為了在執行execute()方法時,盡可能地避免獲取全局鎖(那將會是一個嚴重的可伸縮瓶頸)。在ThreadPoolExecutor完成預熱之后(當前運行的線程數大於等於corePoolSize),幾乎所有的execute()方法調用都是執行步驟2,而步驟2不需要獲取全局鎖。
工作隊列排隊策略
已經說過當線程池中工作線程的總數量超過核心線程數量后,新加的任務就會放入工作隊列中進行等待被執行
使用線程池就得創建ThreadPoolExecutor對象,通過ThreadPoolExecutor(線程池)類的構造方法創建時,就得指定工作隊列,它是BlockingQueue<Runnable>接口,而實際開發中是指定此接口的具體實現類,常用的如下所示。
SynchronousQueue
直接提交策略----意思是工作隊列不保存任何任務被等待執行,而是直接提交給線程進行執行。
工作隊列的默認選項是 SynchronousQueue,它將任務直接提交給線程而不保存它們。
如果不存在可用於立即運行任務的線程,則試圖把任務加入隊列將失敗,因此會構造一個新的線程。
此策略可以避免在處理可能具有內部依賴性的請求集時出現鎖。直接提交通常要求無界 maximumPoolSizes 以避免拒絕新提交的任務。
Executors的newCacheThreadPool()方法創建線程池,就是使用的此種排隊策略
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
 LinkedBlockingQueue
無界隊列策略----無界指的是工作隊列大小沒有上限,可以添加無數個任務進行等待。
使用無界隊列將導致在所有 corePoolSize 線程都忙時新任務在隊列中等待。於是創建的線程就不會超過 corePoolSize。因此,maximumPoolSize 的值也就無效了。所以一般讓corePoolSize等於maximumPoolSize
當每個任務完全獨立於其他任務,即任務執行互不影響時,適合於使用無界隊列 
Executors的newFixedThreadPool(int nThreads)方法創建線程池,就是使用的此種排隊策略
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
ArrayBlockingQueue
有界隊列策略----意思是工作隊列的大小是有限制的
優點是可以防止資源耗盡的情況發生,因為如果工作隊列被無休止的添加任務也是很危險的
當工作隊列排滿后,就會執行線程飽和策略
// 構造線程池
ThreadPoolExecutor threadPool = new ThreadPoolExecutor(3, 4,
3, TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(2),
new ThreadPoolExecutor.DiscardOldestPolicy());
如上核心線程為3個,每個線程的工作隊列大小為2(即隊列中最多有兩個任務在等待執行),線程池最大線程數為4個
所以當工作線程數小於等於3時,直接新建線程執行任務;超過3時,任務會被添加進工作隊列進行等待,3*2=6,當工作隊列等待的任務數超過6個以后,則又會新建一個線程,此時整個線程池線程總數已經達到了4個,當還有任務進行添加時,此時將采取飽和策略
 
————————————————
版權聲明:本文為CSDN博主「蚩尤后裔」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/wangmx1993328/article/details/80582803


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM