juc包下有乙個重要的執行緒池的實現,大大優化方便了我們對執行緒的使用,而不再是傳統的new乙個thread。執行緒池相對傳統的直接建立執行緒主要有三個優點:
1.統一管理執行緒,可以重用存在的執行緒,避免多次的建立、消亡的開銷,使得效能表現得更好
2.可以有效控制最大併發執行緒數,提高系統資源利用率,同時可以避免過多資源的競爭,避免阻塞
3.提供定時執行、定期執行、單執行緒、併發數控制等功能
通過executors工廠方法來建立乙個執行緒池。該工廠方法提供了主要四種重要型別的執行緒池(針對不同應用場景)
這是乙個執行緒數變動性非常強的執行緒池,預設配置下,它可以開啟無限多個執行緒(integer.maxsize 和 jvm允許執行緒數範圍內)。且如果該執行緒池裡的執行緒在60秒內如果是處於空閒狀態(即沒任務執行),那麼該執行緒就會被**,不再由執行緒池維護。如果有新任務進來時,由於之前的執行緒池裡的執行緒已被**,那麼新的執行緒也會再次建立。當執行完任務,60秒內依舊無新任務的可執行話,那麼該執行緒又會被再次**。
綜合該執行緒池的特性,我們可以思考下什麼情況下應該使用這類執行緒池。比如:我們的應用伺服器上面,會在非固定時間(時間跨域度會盡可能大)和非固定的任務數量。
fixedthreadpool乙個固定數量的執行緒池,且該執行緒池不會隨著任務的變化而增多或減少執行緒數量。即該執行緒池下的執行緒池如果你不主動呼叫銷毀shutdowm、purge之類的方法。那麼這些執行緒將會永遠被執行緒池維護著。
singlethreadexecutor是乙個固定單執行緒的執行緒池,該執行緒池會永遠都保持著乙個執行緒的活動狀態,如果該執行緒池的單執行緒因某些異常而退出後,執行緒池會繼續建立乙個新的執行緒。
4.scheduledthreadpool(返回型別是scheduledexecutorservice)
scheduledthreadpool是乙個支援任務定時排程的執行緒池。
執行緒池主要有6大引數,引數的設定是否合理,將會直接影響到執行緒池的效能。
1.corepoolsize(核心執行緒數):在建立了執行緒池後,預設情況下,執行緒池中是沒有執行緒,當有新任務進來時,才會建立新的執行緒去執行這個任務。當再有另外乙個任務進來時,即使剛才的執行緒已經處於空閒狀態,執行緒池也是會建立新的執行緒去執行這個新任務。當執行緒池中的執行緒數達到corepoolsize的時候,就會把新進來的任務放到任務佇列(另乙個重要引數)中。核心執行緒在allowcorethreadtimeout被設定為true時會超時退出,預設情況下不會退出。
2.maxpoolsize(最大執行緒數):當執行緒池中的執行緒數大於等於corepoolsize的時候,而且任務佇列也已經滿了,這個時候,執行緒池就會建立新的執行緒,直到執行緒數目達到maxpoolsize。如果執行緒數目已經達到maxpoolsize,任務佇列又已經滿了,那麼執行緒池則會拒絕處理任務,並丟擲執行時異常(這裡涉及另乙個引數任務拒絕處理器,有四種策略,預設abortpolicy--決絕執行,並丟擲執行時異常)。
3.keepalivetime(執行保空閒時間):當執行緒空閒時間達到keepalivetime,該執行緒會退出,直到執行緒數目等於corepoolsize。如果allowcorethreadtimeout設定為true,則所有執行緒均會退出直到執行緒數量為0。
4.queuecapacity(任務佇列容量):當核心執行緒數達到最大時,新任務會放在佇列中排隊等待執行.
還有就是 workqueue:乙個阻塞佇列,用來儲存等待執行的任務,這個引數的選擇也很重要,會對執行緒池的執行過程產生重大影響,一般來說,這裡的阻塞佇列有以下幾種選擇:
arrayblockingqueue;
linkedblockingqueue;
synchronousqueue;
priorityblockingqueue
5.allowcorethreadtimeout:是否允許核心執行緒空閒退出,預設值為false.
6.rejectedexecutionhandler(任務拒絕處理器):
* 兩種情況會拒絕處理任務:
- 當執行緒數已經達到maxpoolsize,切佇列已滿,會拒絕新任務
- 當執行緒池被呼叫shutdown()後,會等待執行緒池裡的任務執行完畢,再shutdown。如果在呼叫shutdown()和執行緒池真正shutdown之間提交任務,會拒絕新任務
* 執行緒池會呼叫rejectedexecutionhandler來處理這個任務。如果沒有設定預設是abortpolicy,會丟擲異常
* threadpoolexecutor類有幾個內部實現類來處理這類情況:
- abortpolicy 丟棄任務,拋執行時異常
- callerrunspolicy 執行任務
- discardpolicy 忽視,什麼都不會發生
- discardoldestpolicy 從佇列中踢出最先進入佇列(最後乙個執行)的任務
* 實現rejectedexecutionhandler介面,可自定義處理器
1.當執行緒數小於核心執行緒數時,建立執行緒。
2.當執行緒數大於等於核心執行緒數,且任務佇列未滿時,將任務放入任務佇列。
3.當執行緒數大於等於核心執行緒數,且任務佇列已滿。
1.若執行緒數小於最大執行緒數,建立執行緒。
2.若執行緒數等於最大執行緒數,丟擲異常,拒絕任務。
corepoolsize設定
每個任務需要tasktime秒處理,則每個執行緒每鈔可處理1/tasktime個任務。系統每秒有tasks個任務需要處理,則需要的執行緒數為:tasks/(1/tasktime),即tasks*tasktime個執行緒數。假設系統每秒任務數為100~1000,每個任務耗時0.1秒,則需要100*0.1至1000*0.1,即10~100個執行緒。那麼corepoolsize應該設定為大於10,具體數字最好根據8020原則,即80%情況下系統每秒任務數,若系統80%的情況下第秒任務數小於200,最多時為1000,則corepoolsize可設定為20。
queuecapacity設定
任務佇列的長度要根據核心執行緒數,以及系統對任務響應時間的要求有關。佇列長度可以設定為(corepoolsize/tasktime)*responsetime: (20/0.1)*2=400,即佇列長度可設定為400。
佇列長度設定過大,會導致任務響應時間過長,切忌以下寫法:
這實際上是將佇列長度設定為integer.max_value,將會導致執行緒數量永遠為corepoolsize,再也不會增加,當任務數量陡增時,任務響應時間也將隨之陡增。
maxpoolsize設定
當系統負載達到最大值時,核心執行緒數已無法按時處理完所有任務,這時就需要增加執行緒。每秒200個任務需要20個執行緒,那麼當每秒達到1000個任務時,則需要(1000-queuecapacity)*(20/200),即60個執行緒,可將maxpoolsize設定為60。
keepalivetime設定
執行緒數量只增加不減少也不行。當負載降低時,可減少執行緒數量,如果乙個執行緒空閒時間達到keepalivetiime,該執行緒就退出。預設情況下執行緒池最少會保持corepoolsize個執行緒。
allowcorethreadtimeout設定
預設情況下核心執行緒不會退出,可通過將該引數設定為true,讓核心執行緒也退出。
rejectedexecutionhandler設定
設定預設是abortpolicy,會丟擲異常。
Java併發之執行緒池的學習
相較執行緒,執行緒池的好處 1 減少在建立和銷毀執行緒上所花的時間以及系統資源的開銷 2 可以重複利用執行緒池中已建立的執行緒 直接介紹常見的幾種執行緒池 1 newfixedthreadpool int nthreads 建立乙個固定數量執行緒集合的執行緒池。新的執行緒加入後,如果正在執行的執行緒...
java學習筆記 執行緒池
1.為什麼有執行緒池?既然是乙個存放執行緒的池子,那麼,執行緒池的工作要務肯定就是控制管理執行的執行緒啦。既然要 原理,我們肯定得從原始碼說起了。我們先來介紹一下四個常見的執行緒池 四個基本執行緒池 建立單個執行緒 executors.newsinglethreadexecutor public s...
java併發程式設計學習11 執行緒池
執行緒池 為了節省系統在多執行緒併發時不斷建立和銷毀執行緒帶來的額外開銷,就需要引入執行緒池。執行緒池的基本功能就是進行執行緒的復用。當系統接受一 個提交的任務時,並不會著急去建立乙個新的執行緒去執行這個任務,而是去執行緒池中查詢是否有空閒的執行緒。若有 直接使用這個執行緒。若沒有 根據配置的策略執...