阿里代碼規(guī)范為什么不允許使用Executors快速創(chuàng)建線程池?(源碼分析!)

先簡(jiǎn)單聊一下快速創(chuàng)建常用的四個(gè)線程池,預(yù)備知識(shí),當(dāng)然面試題也會(huì)考啦:

1.newFixedThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待。
2.newCachedThreadPool創(chuàng)建一個(gè)可緩存線程池,如果線程池長(zhǎng)度超過(guò)處理需要,可靈活回收空閑線程,若無(wú)可回收,則新建線程。
3.newScheduledThreadPool 創(chuàng)建一個(gè)定長(zhǎng)線程池,支持定時(shí)及周期性任務(wù)執(zhí)行。
4.newSingleThreadExecutor 創(chuàng)建一個(gè)單線程化的線程池,它只會(huì)用唯一的工作線程來(lái)執(zhí)行任務(wù),保證所有任務(wù)按照指定順序(FIFO, LIFO, 優(yōu)先級(jí))執(zhí)行。

先來(lái)看下用線程池處理任務(wù)的時(shí)候的場(chǎng)景:
線程池里有我們的線程和一個(gè)隊(duì)列,線程又分核心線程非核心線程(空閑超出一定時(shí)間會(huì)被消滅),隊(duì)列的話就是如果核心線程創(chuàng)建滿了,就把任務(wù)放到隊(duì)列中,如果隊(duì)列也放滿了,那就再創(chuàng)建非核心線程,那如果非核心線程也創(chuàng)建滿了呢?那就涉及到拒絕策略了,在后面會(huì)講。

abcc8e405d1d4b3c384ad56cc8d28745_1539943510290485858e761.jpg

再來(lái)看看ThreadPoolExecutor的構(gòu)造方法,有好多,就直接看最多參數(shù)的那個(gè)吧

x.png

}X(Q~ZTZ2_TYA`LF}@V_XTG.png

corePoolSize 線程池的基本大小, 當(dāng)提交一個(gè)任務(wù)到線程池的時(shí)候,線程池會(huì)創(chuàng)建一個(gè)線程來(lái)執(zhí)行任務(wù),即使當(dāng)前線程池已經(jīng)存在空閑線程,仍然會(huì)創(chuàng)建一個(gè)線程,等到需要執(zhí)行的任務(wù)數(shù)大于線程池基本大小時(shí)就不再創(chuàng)建。

maximumPoolSizeSize 線程池最大數(shù)量,線程池允許創(chuàng)建的最大線程數(shù),如果隊(duì)列滿了,并且已創(chuàng)建的線程數(shù)小于最大線程數(shù),則線程池會(huì)再創(chuàng)建新的線程執(zhí)行任務(wù)。值得注意的是,如果使用了無(wú)界的任務(wù)隊(duì)列這個(gè)參數(shù)就沒(méi)什么效果。

keepAliveTime 線程活動(dòng)保持時(shí)間,線程池的工作線程空閑后,保持存活的時(shí)間(針對(duì)非核心線程),所以,如果任務(wù)很多,并且每個(gè)任務(wù)執(zhí)行的時(shí)間比較短,可以調(diào)大時(shí)間,提高線程的利用率。
但是如果調(diào)用了allowCoreThreadTimeOut(boolean)方法(開(kāi)始針對(duì)核心線程啦),在線程池中的線程數(shù)不大于corePoolSize時(shí),keepAliveTime參數(shù)也會(huì)起作用,直到線程池中的線程數(shù)為0;

unit 線程活動(dòng)保持時(shí)間的單位,可選擇的單位有時(shí)分秒等等。

workQueue 任務(wù)隊(duì)列。用來(lái)暫時(shí)保存任務(wù)的工作隊(duì)列,需要是BlockingQueue的實(shí)現(xiàn)

threadFactory:是構(gòu)造 Thread 的方法,一個(gè)接口類,可以使用默認(rèn)的 default實(shí)現(xiàn),也可以自己去包裝和傳遞,主要實(shí)現(xiàn) newThread 方法即可;

handler 拒絕策略,如果線程池滿了,而且有界隊(duì)列也滿了,對(duì)新添加進(jìn)來(lái)的任務(wù)的處理方式

其實(shí)這四種線程在內(nèi)部也是自己實(shí)現(xiàn)了ThreadPoolExecutor的構(gòu)造方法,一起來(lái)看看吧

newFixedThreadPool

WMWQOEH_1JJP4A~)TF(5_M3.png

看的出來(lái)什么不,核心線程和最大線程數(shù)是一樣的,但是用了LinkedBlockingQueue,而且沒(méi)有賦大小值,這可是個(gè)無(wú)界隊(duì)列啊!任務(wù)一多全放進(jìn)這隊(duì)列里,分分鐘OOM。

newCachedThreadPool

22.png

好了,咱們這次沒(méi)有核心線程了,也用了有界隊(duì)列了,但是這Integer.MAX_VALUE是什么鬼,人任務(wù)進(jìn)來(lái)一個(gè)你new一個(gè)唄,線程無(wú)限創(chuàng)建,也要OOM。
SynchronousQueue沒(méi)有容量,是無(wú)緩沖等待隊(duì)列,是一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列,會(huì)直接將任務(wù)交給消費(fèi)者,必須等隊(duì)列中的添加元素被消費(fèi)后才能繼續(xù)添加新的元素。

newScheduledThreadPool

OD}0}VRH}%51`Y3P885HKUJ.png

跟咱們CachedThreadPool一個(gè)毛病,雖然這個(gè)DelayedWorkQueue是有界隊(duì)列(看下圖,默認(rèn)大小為16),但是你線程最大數(shù)是Integer.MAX_VALUE,OOM!

1.png

newSingleThreadExecutor

@5`6T%~{5K179HDEU(KJ`~4.png

總算輪到最后一個(gè)了,這個(gè)好分析,還是用了無(wú)界隊(duì)列的問(wèn)題,任務(wù)過(guò)來(lái)就放到隊(duì)列里,會(huì)導(dǎo)致隊(duì)列特別長(zhǎng)從而OOM。

拒絕策略

ThreadPoolExecutor.AbortPolicy:直接拋出異常
ThreadPoolExecutor.DiscardPolicy:不處理,丟棄掉
ThreadPoolExecutor.DiscardOldestPolicy:丟棄最老的。也就是說(shuō)如果隊(duì)列滿了,會(huì)將最早進(jìn)入隊(duì)列的任務(wù)刪掉騰出空間,再嘗試加入隊(duì)列。因?yàn)殛?duì)列是隊(duì)尾進(jìn),隊(duì)頭出,所以隊(duì)頭元素是最老的,因此每次都是移除對(duì)頭元素后再嘗試入隊(duì)。
ThreadPoolExecutor.CallerRunsPolicy:直接調(diào)用這個(gè)線程池所在的線程來(lái)運(yùn)行任務(wù)(如果線程池在main方法創(chuàng)建的話,任務(wù)就交給main方法)
發(fā)現(xiàn)網(wǎng)上已經(jīng)有比較好的博客,而且比較好理解,就不重復(fù)造輪子啦
線程池的RejectedExecutionHandler(拒絕策略)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 什么是線程池 線程池可以通過(guò)池看出來(lái)是一個(gè)資源集,任何池的作用都大同小異,主要是用來(lái)減少資源創(chuàng)建、初始化的系統(tǒng)開(kāi)銷...
    步二小哥閱讀 666評(píng)論 0 0
  • 深入分析線程池 在前面的文章中,我們使用線程的時(shí)候就去創(chuàng)建一個(gè)線程,這樣實(shí)現(xiàn)起來(lái)非常簡(jiǎn)便,但是就會(huì)有一個(gè)問(wèn)題: 如...
    史路比閱讀 505評(píng)論 0 1
  • #玩卡不卡·每日一抽#每一位都可以通過(guò)這張卡片覺(jué)察自己: 1、直覺(jué)他叫什么名字?小剛 2、他幾歲了?25 3、他現(xiàn)...
    我心安住閱讀 186評(píng)論 0 0
  • 本文作者就是我,簡(jiǎn)書的microkof。如果您覺(jué)得本文對(duì)您的工作有意義,產(chǎn)生了不可估量的價(jià)值,那么請(qǐng)您不吝打賞我,...
    microkof閱讀 23,852評(píng)論 16 78
  • 早上紅紅的太陽(yáng)從東邊升起,溫暖的陽(yáng)光照在我的身上。我看見(jiàn)我的影子變得長(zhǎng)長(zhǎng)的,瘦瘦的。中午的時(shí)候陽(yáng)光很強(qiáng)烈,比上午的...
    商紫燁閱讀 104評(píng)論 0 0

友情鏈接更多精彩內(nèi)容