先簡(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.pngcorePoolSize 線程池的基本大小, 當(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(拒絕策略)







