最近在給小伙伴說(shuō)明線(xiàn)程池技術(shù)的時(shí)候恩急,用到了一個(gè)例子假栓,發(fā)現(xiàn)比較適合匾荆,在這記錄一下。
很多書(shū)籍和文章都會(huì)說(shuō)牙丽,如果請(qǐng)求很多的話(huà)烤芦,頻繁的創(chuàng)建和銷(xiāo)毀線(xiàn)程容易造成資源的消耗和浪費(fèi)构罗,降低系統(tǒng)的響應(yīng),這個(gè)時(shí)候遂唧,需要對(duì)線(xiàn)程進(jìn)行的統(tǒng)一分配盖彭、監(jiān)控、管理铺呵,線(xiàn)程池技術(shù)就派上用場(chǎng)了。
先看一下Java中關(guān)于線(xiàn)程池 ThreadPoolExecutor 的創(chuàng)建
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)
分別對(duì)這幾個(gè)參數(shù)做一個(gè)說(shuō)明:
- corePoolSize :核心線(xiàn)程數(shù),線(xiàn)程池中可以長(zhǎng)期存在的線(xiàn)程數(shù)量贱鼻,即使沒(méi)有任務(wù)提交到線(xiàn)程池滋将,也不會(huì)被銷(xiāo)毀。
- maximumPoolSize :最大線(xiàn)程數(shù)父丰,線(xiàn)程池中最多可以創(chuàng)建來(lái)執(zhí)行任務(wù)的線(xiàn)程上限蛾扇。
- keepAliveTime :存活時(shí)間,超過(guò) maximumPoolSize 數(shù)量外的線(xiàn)程的存活時(shí)間坟漱,超過(guò)這個(gè)時(shí)間沒(méi)有執(zhí)行任務(wù)時(shí)會(huì)被銷(xiāo)毀芋齿。
- TimeUnit : keepAliveTime 的單位成翩。
- workQueue : 任務(wù)隊(duì)列,沒(méi)有得到執(zhí)行的任務(wù)栅炒,會(huì)放入這個(gè)隊(duì)列中等待空閑的線(xiàn)程來(lái)執(zhí)行它赢赊。
- threadFactory : 線(xiàn)程工廠(chǎng)级历,定義創(chuàng)建新線(xiàn)程的方式鱼喉,包括線(xiàn)程名稱(chēng),線(xiàn)程組等锋边。
- handler :拒絕策略豆巨,當(dāng) workQueue 已滿(mǎn)掐场,并且 線(xiàn)程數(shù)量達(dá)到了maximumPoolSize熊户,會(huì)對(duì)新提交的任務(wù)執(zhí)行拒絕策略。
再來(lái)看看線(xiàn)程池的工作原理:
- 如果線(xiàn)程池中的線(xiàn)程數(shù)量沒(méi)超過(guò)corePoolSize蝗罗,創(chuàng)建一個(gè)新線(xiàn)程來(lái)執(zhí)行任務(wù)串塑。
- 如果線(xiàn)程池中的線(xiàn)程數(shù)量達(dá)到corePoolSize,將任務(wù)放入workQueue桩匪。
- 如果workQueue已滿(mǎn),線(xiàn)程池中的線(xiàn)程數(shù)量沒(méi)超過(guò)maximumPoolSize瑟慈,創(chuàng)建新線(xiàn)程來(lái)執(zhí)行任務(wù)葛碧。
- 線(xiàn)程池中的線(xiàn)程執(zhí)行完一個(gè)任務(wù)后进泼,會(huì)從workQueue取任務(wù)執(zhí)行。
- 超過(guò)corePoolSize的線(xiàn)程如果空閑超過(guò)keepAliveTime沒(méi)有執(zhí)行任務(wù)纤虽,就要進(jìn)行銷(xiāo)毀乳绕。
- 如果workQueue已滿(mǎn),且線(xiàn)程池中的線(xiàn)程數(shù)量達(dá)到maximumPoolSize逼纸,執(zhí)行拒絕策略 handler洋措。
- - - - - - - - - - - - - - 這是一個(gè)分割線(xiàn) - - - - - - - - - - - - -
上邊就是官網(wǎng)中對(duì)線(xiàn)程池參數(shù)的一些說(shuō)明,這一個(gè)個(gè)參數(shù)看起來(lái)都什么玩意兒杰刽,說(shuō)的是人話(huà)嗎菠发,好吧,那我們用生活中的例子來(lái)重新說(shuō)明一下贺嫂。
首先滓鸠,為什么要是用線(xiàn)程池技術(shù),為什么說(shuō)創(chuàng)建和銷(xiāo)毀線(xiàn)程會(huì)消耗資源
讓我們想象一下第喳,有一個(gè)旅游村(假設(shè)叫象牙村吧)住著一戶(hù)人家曲饱,就叫 老王 吧(不是老王八)楔敌,經(jīng)常有來(lái)旅游的人來(lái)化個(gè)緣吃個(gè)飯侵浸,這時(shí)候,老王把桌子椅子擺上值漫,讓這個(gè)人坐好沥邻,然后根據(jù)這個(gè)人的需要把他要吃的飯做好埃跷,等這個(gè)人吃完飯走了之后,把桌子椅子收拾好剪勿。假設(shè)來(lái)吃飯的人不多的話(huà)還好,來(lái)一個(gè)人就臨時(shí)擺個(gè)桌子椅子就行赴涵;但是如果來(lái)吃飯的人很多,每次都要先把椅子擺好,等一個(gè)人吃完程拭,把桌椅收起來(lái)崖媚,再把桌椅搬出來(lái)給下一個(gè)人用,這樣反反復(fù)復(fù)荠呐,很浪費(fèi)搬桌子的時(shí)間。這個(gè)時(shí)候,老王想:來(lái)旅游人也挺多的钞钙,我干脆開(kāi)個(gè)飯店得了。
線(xiàn)程池技術(shù)應(yīng)運(yùn)而生:
- 線(xiàn)程就相當(dāng)于吃飯的桌子焕议,每張桌子要配備一個(gè)服務(wù)員
- 飯店就相當(dāng)于線(xiàn)程池
接著,線(xiàn)程池里的參數(shù)對(duì)應(yīng)過(guò)來(lái)代表什么意思:
- corePoolSize :飯店大廳的桌子數(shù),能供多少人共同吃飯蝙寨,就算沒(méi)人來(lái)吃飯贝奇,這個(gè)桌子也不會(huì)收起來(lái)毕源。
- maximumPoolSize :最多桌子數(shù),大廳坐不下了必盖,飯店在院子里再擺新的桌子拍埠。
- keepAliveTime :存活時(shí)間,院子里的桌子多長(zhǎng)時(shí)間沒(méi)人用了棉圈,就要收起來(lái)。
- TimeUnit : keepAliveTime 的單位吁系。
- workQueue : 飯店大廳坐滿(mǎn)了的話(huà)蕴坪,就要先排隊(duì)呆瞻。
- threadFactory : 生產(chǎn)桌子的方式,知道是哪個(gè)飯店第幾桌买窟。這個(gè)有什么用呢话侄?如果不指定的話(huà)吞杭,假設(shè)老王開(kāi)了個(gè)飯店童擎,老李開(kāi)了個(gè)飯店芯砸,他們都沒(méi)有自己指定的桌子供貨商,那就默認(rèn)使用村子里生產(chǎn)的桌子,按順序的話(huà)就是 象牙村1號(hào)桌、象牙村2號(hào)桌,萬(wàn)一發(fā)生了意外,客人吃著吃著肚子不舒服矾策,或者這一桌的客人喝大了打了起來(lái)蓬豁,只知道是 象牙村X(qián)號(hào)桌 出了問(wèn)題,不知道該找老王還是老李矛辕,但是如果他們有自己的供貨商翻屈,桌子就變成了老王飯店1號(hào)桌惊窖,老李飯店9號(hào)桌毁欣,出了問(wèn)題串述,能夠溯源。所以一般建議大家使用自己的線(xiàn)程工廠(chǎng),按業(yè)務(wù)對(duì)線(xiàn)程進(jìn)行命名欣簇。
- handler :當(dāng)排隊(duì)的隊(duì)伍排滿(mǎn)了闹丐,院子里也坐滿(mǎn)了人,就要對(duì)新來(lái)的人執(zhí)行拒絕策略缘挽。
最后摹蘑,看看怎么用這個(gè)例子來(lái)解釋線(xiàn)程池的工作原理:
- 有一個(gè)客人要來(lái)吃飯的時(shí)候踪少,如果飯店大廳沒(méi)有坐滿(mǎn),就在大廳擺上桌椅纬霞,讓這個(gè)客人吃飯。
- 如果大廳坐滿(mǎn)了横蜒,新來(lái)的人就要在門(mén)口的椅子上坐著排隊(duì)茵乱,等待輪到自己的順序次询,這個(gè)椅子可以限制數(shù)量,比如只排50個(gè)人,也可以不限制虹蓄。
- 如果門(mén)口排隊(duì)的椅子已經(jīng)坐滿(mǎn)了累铅,說(shuō)明今天來(lái)吃飯的人實(shí)在太多娃兽,老王就要看看還有沒(méi)有多余的桌子玛荞,有的話(huà)客蹋,就在院子里把桌子擺上給新來(lái)的人吃飯娩井。
- 一旦某一桌的客人吃完走了之后仔粥,這張桌子服務(wù)員就會(huì),就從門(mén)口排隊(duì)的客人里讓最靠前的進(jìn)店吃飯蟹但。
- 院子里的桌子如果一段時(shí)間沒(méi)人吃飯躯泰,說(shuō)明過(guò)了吃飯的高峰期,客人不那么多了华糖,超過(guò)keepAliveTime的空閑麦向,就要把桌子收起來(lái),這個(gè)服務(wù)員也回去休息客叉。
- 如果門(mén)口排隊(duì)的椅子已經(jīng)坐滿(mǎn)诵竭,店里的桌子也都用完,要執(zhí)行相應(yīng)的拒絕策略兼搏。有這么幾種策略
1. AbortPolicy :默認(rèn)的卵慰,拋出一個(gè)異常。相當(dāng)于用大喇叭喊了一下:“本店吃飯人數(shù)太多啦佛呻,大家別擠了”裳朋。
2. DiscardPolicy :直接丟棄。相當(dāng)于跟客人說(shuō)吓著,現(xiàn)在人太多鲤嫡,不接待新客戶(hù)了。
3. DiscardOldestPolicy :丟棄排隊(duì)最久的任務(wù)夜矗。相當(dāng)于讓門(mén)口椅子上排第一個(gè)的人出去泛范,意思是,你都排這么久了紊撕,看來(lái)你也不餓,那你就別吃了吧赡突。
4. CallerRunsPolicy :接待者執(zhí)行对扶,意思就是在門(mén)口迎賓的那個(gè)人,把自己坐的桌子讓出來(lái)給客人吃飯惭缰,但在這個(gè)客人吃完之前浪南,他就沒(méi)法再接待新的客人了。
再補(bǔ)充一下關(guān)于停止線(xiàn)程池的2個(gè)方法漱受,這兩個(gè)方法都會(huì)拒絕新任務(wù)络凿,相當(dāng)于說(shuō)本店打烊了,不接待新客戶(hù),它們之間的區(qū)別在于:
- shutdown() :允許在關(guān)店之前已經(jīng)來(lái)店里的客人把飯吃完絮记。
- shutdownNow() :不但不讓正在排隊(duì)的客人進(jìn)店吃飯摔踱,還會(huì)嘗試把在店里沒(méi)吃完的客人趕出去。這個(gè)方法比較暴力怨愤。