關於執行緒池ThreadPoolExecutor引數設定那些事
由於近期工作需要,最近需要測試開發某元件(該元件中用到了ThreadPoolExecutor)的效能,測試工具是soapUI,由於以前對測試效能方面接觸較少。所以藉此機會再網上查閱了相關資料,總結如下。
執行緒數到底和什麼有關係?
其中一種說法,是執行緒數和cpu數有關係。
總體意思是,當應用是IO密集型時,執行緒數T=2N+1.
當應用是CPU密集型時, 執行緒數T=N+1
T=執行緒數 N=cpu邏輯盒數
IO密集型應用
CPU密集型應用:系統的硬碟、記憶體效能相對CPU要好很多,CPU要讀/寫I/O(硬碟/記憶體),I/O在很短的時間就可以完 成,而CPU還有許多運算要處理,CPU Loading很高。
如果上面對IO和CPU密集型應用解釋不好理解,簡單講如果你的應用大部分是I/O讀寫操作,很少複雜高頻的運算,cpu 大部分是等待I/O運算,那麼你的應用就是IO密集型應用;如果你的應用很少讀寫操作,基本都是高頻且複雜的各種運算,cpu大部分時間都很忙,那麼你的應用是CPU密集型應用。一般情況我們的應用都是I/O密集型應用。
另外一種說法,是ThreadPoolExecutor執行緒池設定和實際併發量有關係。
1、先簡單說下執行緒池ThreadPoolExecutor的幾個引數的意思:
corePoolSize:核心執行緒數
核心執行緒會一直存活,及時沒有任務需要執行
當執行緒數小於核心執行緒數時,即使有執行緒空閒,執行緒池也會優先建立新執行緒處理
設定allowCoreThreadTimeout=true(預設false)時,核心執行緒會超時關閉
queueCapacity:任務佇列容量(阻塞佇列)
當核心執行緒數達到最大時,新任務會放在佇列中排隊等待執行
maxPoolSize:最大執行緒數
當執行緒數>=corePoolSize,且任務佇列已滿時。執行緒池會建立新執行緒來處理任務
當執行緒數=maxPoolSize,且任務佇列已滿時,執行緒池會拒絕處理任務而丟擲異常
keepAliveTime:執行緒空閒時間
當執行緒空閒時間達到keepAliveTime時,執行緒會退出,直到執行緒數量=corePoolSize
如果allowCoreThreadTimeout=true,則會直到執行緒數量=0
allowCoreThreadTimeout:為true時允許核心執行緒超時,即核心執行緒空閒時間超時也可以退出
rejectedExecutionHandler:任務拒絕處理器
ThreadPoolExecutor執行順序:
當執行緒數小於核心執行緒數時,來了新任務就建立新執行緒,即使有空閒執行緒。
當執行緒數大於等於核心執行緒數,且任務佇列未滿時,將任務放入任務佇列。
當執行緒數大於等於核心執行緒數,且任務佇列已滿
若執行緒數小於最大執行緒數,建立執行緒
若執行緒數等於最大執行緒數,丟擲異常,拒絕任務
2、再說下如何設定執行緒池的引數,需要根據幾個值來決定。
tasks :每秒的任務併發數,假設為500~1000
taskcost:每個任務花費時間,假設為0.1s(可以依據soapUI的平均時間avg引數)
responsetime:系統允許容忍的最大響應時間,假設為1s
做幾個計算
corePoolSize = 每秒需要多少個執行緒處理?
threadcount = tasks/(1/taskcost) =tasks*taskcout = (500~1000)*0.1 = 50~100 個執行緒。corePoolSize設定應該大於50
根據8020原則,如果80%的每秒任務數小於800,那麼corePoolSize設定為80即可
queueCapacity = (coreSizePool/taskcost)*responsetime
計算可得 queueCapacity = 80/0.1*1 = 80。意思是佇列裡的執行緒可以等待1s,超過了的需要新開執行緒來執行
切記不能設定為Integer.MAX_VALUE,這樣佇列會很大,執行緒數只會保持在corePoolSize大小,當任務陡增時,不能新 開執行緒來執行,響應時間會隨之陡增。
maxPoolSize = (max(tasks)- queueCapacity)/(1/taskcost)
計算可得 maxPoolSize = (1000-80)/10 = 92
(最大任務數-佇列容量)/每個執行緒每秒處理能力 = 最大執行緒數
rejectedExecutionHandler:根據具體情況來決定,任務不重要可丟棄,任務重要則要利用一些緩衝機制來處理
keepAliveTime和allowCoreThreadTimeout採用預設通常能滿足
總結:到底執行緒數設定根據什麼依據設定,需要各位根據自己機器情況和實際併發量,都測試下,看那個更好選擇哪種設定方案。一般情況,我比較關注三個引數來判斷執行緒池是否配置合理,併發量、avg、tps、cpu使用率。
假如併發量在50-150之間,我的執行緒執行時間大概是5ms左右,tps在65-200,cpu使用率在30%-70%,這個資料就不是很理想。當然這些測試是在本地筆記本並非伺服器上。