如果并發(fā)的請(qǐng)求數(shù)量非常多,但每個(gè)線程執(zhí)行的時(shí)間很短舔痪,這樣就會(huì)頻繁的創(chuàng)建和銷毀線程寓调,如此一來會(huì)大大降低系統(tǒng)的效率。這就是線程池的目的了锄码。線程池為線程生命周期的開銷和資源不足問題提供了解決方案夺英。通過對(duì)多個(gè)任務(wù)重用線程,線程創(chuàng)建的開銷被分?jǐn)偟搅硕鄠€(gè)任務(wù)上滋捶。
線程池主要流程
用戶通過submit提交一個(gè)任務(wù),線程池會(huì)執(zhí)行如下流程:
- 判斷當(dāng)前運(yùn)行的worker數(shù)量是否超過corePoolSize,如果不超過corePoolSize痛悯。就創(chuàng)建一個(gè)worker直接執(zhí)行該任務(wù)≈乜撸—— 線程池最開始是沒有worker在運(yùn)行的
- 如果正在運(yùn)行的worker數(shù)量超過或者等于corePoolSize,那么就將該任務(wù)加入到workQueue隊(duì)列中去载萌。
- 如果workQueue隊(duì)列滿了,也就是offer方法返回false的話,就檢查當(dāng)前運(yùn)行的worker數(shù)量是否小于maximumPoolSize,如果小于就創(chuàng)建一個(gè)worker直接執(zhí)行該任務(wù)巡扇。
- 如果當(dāng)前運(yùn)行的worker數(shù)量是否大于等于maximumPoolSize扭仁,那么就執(zhí)行RejectedExecutionHandler來拒絕這個(gè)任務(wù)的提交。
- workQueue:任務(wù)的阻塞隊(duì)列厅翔,緩存將要執(zhí)行的Runnable任務(wù)乖坠,由各線程輪詢?cè)撊蝿?wù)隊(duì)列獲取任務(wù)執(zhí)行〉睹疲可以選擇以下幾個(gè)阻塞隊(duì)列:
- ArrayBlockingQueue:是一個(gè)基于數(shù)組結(jié)構(gòu)的有界阻塞隊(duì)列熊泵,此隊(duì)列按 FIFO(先進(jìn)先出)原則對(duì)元素進(jìn)行排序。
- LinkedBlockingQueue:一個(gè)基于鏈表結(jié)構(gòu)的阻塞隊(duì)列甸昏,此隊(duì)列按FIFO (先進(jìn)先出) 排序元素顽分,吞吐量通常要高于ArrayBlockingQueue。靜態(tài)工廠方法Executors.newFixedThreadPool()使用了這個(gè)隊(duì)列施蜜。
- SynchronousQueue:一個(gè)不存儲(chǔ)元素的阻塞隊(duì)列怯邪。每個(gè)插入操作必須等到另一個(gè)線程調(diào)用移除操作,否則插入操作一直處于阻塞狀態(tài)花墩,吞吐量通常要高于LinkedBlockingQueue悬秉,靜態(tài)工廠方法Executors.newCachedThreadPool使用了這個(gè)隊(duì)列。
- PriorityBlockingQueue:一個(gè)具有優(yōu)先級(jí)的無限阻塞隊(duì)列冰蘑。
線程池的飽和策略
注: 當(dāng)線程池的飽和策略和泌,當(dāng)阻塞隊(duì)列滿了,且沒有空閑的工作線程祠肥,如果繼續(xù)提交任務(wù)武氓,必須采取一種策略處理該任務(wù),線程池提供了4種策略:
- ThreadPoolExecutor.AbortPolicy:丟棄任務(wù)并拋出RejectedExecutionException異常。
- ThreadPoolExecutor.DiscardPolicy:也是丟棄任務(wù)县恕,但是不拋出異常东羹。
- ThreadPoolExecutor.DiscardOldestPolicy:丟棄隊(duì)列最前面的任務(wù),然后重新嘗試執(zhí)行任務(wù)(重復(fù)此過程)
- ThreadPoolExecutor.CallerRunsPolicy:由調(diào)用線程處理該任務(wù)
線程池的狀態(tài)(5種):
其中AtomicInteger變量ctl的功能非常強(qiáng)大:利用低29位表示線程池中線程數(shù)忠烛,通過高3位表示線程池的運(yùn)行狀態(tài):
- RUNNING:-1 << COUNT_BITS属提,即高3位為111,該狀態(tài)的線程池會(huì)接收新任務(wù)美尸,并處理阻塞隊(duì)列中的任務(wù)冤议;
- SHUTDOWN: 0 << COUNT_BITS,即高3位為000师坎,該狀態(tài)的線程池不會(huì)接收新任務(wù)恕酸,但會(huì)處理阻塞隊(duì)列中的任務(wù);
- STOP : 1 << COUNT_BITS胯陋,即高3位為001蕊温,該狀態(tài)的線程不會(huì)接收新任務(wù),也不會(huì)處理阻塞隊(duì)列中的任務(wù)遏乔,而且會(huì)中斷正在運(yùn)行的任務(wù)义矛;
- TIDYING : 2 << COUNT_BITS,即高3位為010按灶,該狀態(tài)表示線程池對(duì)線程進(jìn)行整理優(yōu)化症革;
- TERMINATED: 3 << COUNT_BITS筐咧,即高3位為011鸯旁,該狀態(tài)表示線程池停止工作;
如何創(chuàng)建線程池
Executors工廠類
- Executors.newCachedThreadPool();
說明: 創(chuàng)建一個(gè)可緩存線程池量蕊,如果線程池長(zhǎng)度超過處理需要铺罢,可靈活回收空閑線程,若無可回收残炮,則新建線程. - Executors.newFixedThreadPool(int);
說明: 創(chuàng)建一個(gè)定長(zhǎng)線程池韭赘,可控制線程最大并發(fā)數(shù),超出的線程會(huì)在隊(duì)列中等待势就。 - Executors.newSingleThreadExecutor();
說明:創(chuàng)建一個(gè)單線程化的線程池泉瞻,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照順序執(zhí)行苞冯。 - Executors.newScheduledThreadPool(int);
說明:創(chuàng)建一個(gè)定長(zhǎng)線程池袖牙,支持定時(shí)及周期性任務(wù)執(zhí)行。
弊端:
- FixedThreadPool 和 SingleThreadPool:
允許的請(qǐng)求隊(duì)列長(zhǎng)度為 Integer.MAX_VALUE舅锄,可能會(huì)堆積大量的請(qǐng)求鞭达,從而導(dǎo)致 OOM。 - CachedThreadPool 和 ScheduledThreadPool:
允許的創(chuàng)建線程數(shù)量為 Integer.MAX_VALUE, 可能會(huì)創(chuàng)建大量的線程畴蹭,從而導(dǎo)致 OOM坦仍。
ThreadPoolExecutor
雖然上述Executors提供了工具類,但是依然存在可能會(huì)導(dǎo)致OOM的問題叨襟,我們一般建議采用SDK內(nèi)部的線程池來創(chuàng)建繁扎,同時(shí)也可以讓使用者了解每個(gè)參數(shù)的含義,防止出現(xiàn)問題芹啥。
SDK內(nèi)部提供了創(chuàng)建線程池的構(gòu)造方法,如下:
/**
* @param corePoolSize:核心線程數(shù)锻离;
* @param maximumPoolSize:線程池允許的最大線程數(shù);
* @param keepAliveTime:保持活動(dòng)時(shí)間墓怀,空閑的線程(普通線程)在超過keepAliveTime時(shí)間內(nèi)沒有被復(fù)用汽纠,就被銷毀;
* @param unit:時(shí)間單位傀履;
* @param workQueue:任務(wù)隊(duì)列虱朵,用來存儲(chǔ)已經(jīng)被提交,即將被執(zhí)行的任務(wù)钓账;
* @param threadFactory:線程工廠碴犬,用來創(chuàng)建線程池中的線程;
* @param handler:拒絕策略梆暮,線程池關(guān)閉服协,或者最大線程數(shù)和隊(duì)列已經(jīng)飽和的情況下,拋出RejectedExecutionException異常啦粹;
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
}