2023-07-11 10:26:21來源:今日頭條
下圖所示為線程池的實(shí)現(xiàn)原理:調(diào)用方不斷地向線程池中提交任務(wù);線程池中有一組線程,不斷地 從隊(duì)列中取任務(wù),這是一個(gè)典型的生產(chǎn)者—消費(fèi)者模型。
【資料圖】
要實(shí)現(xiàn)這樣一個(gè)線程池,有幾個(gè)問題需要考慮:
1. 隊(duì)列設(shè)置多長(zhǎng)?如果是無界的,調(diào)用方不斷地往隊(duì)列中放任務(wù),可能導(dǎo)致內(nèi)存耗盡。如果是有 界的,當(dāng)隊(duì)列滿了之后,調(diào)用方如何處理?
2. 線程池中的線程個(gè)數(shù)是固定的,還是動(dòng)態(tài)變化的?
3. 每次提交新任務(wù),是放入隊(duì)列?還是開新線程?
4. 當(dāng)沒有任務(wù)的時(shí)候,線程是睡眠一小段時(shí)間?還是進(jìn)入阻塞?如果進(jìn)入阻塞,如何喚醒?
針對(duì)問題4,有3種做法:
1. 不使用阻塞隊(duì)列,只使用一般的線程安全的隊(duì)列,也無阻塞/喚醒機(jī)制。當(dāng)隊(duì)列為空時(shí),線程 池中的線程只能睡眠一會(huì)兒,然后醒來去看隊(duì)列中有沒有新任務(wù)到來,如此不斷輪詢。
2. 不使用阻塞隊(duì)列,但在隊(duì)列外部、線程池內(nèi)部實(shí)現(xiàn)了阻塞/喚醒機(jī)制。
3. 使用阻塞隊(duì)列。
很顯然,做法3最完善,既避免了線程池內(nèi)部自己實(shí)現(xiàn)阻塞/喚醒機(jī)制的麻煩,也避免了做法1的睡 眠/輪詢帶來的資源消耗和延遲。正因?yàn)槿绱?,接下來要講的ThreadPoolExector/ScheduledThreadPoolExecutor都是基于阻塞隊(duì)列來實(shí)現(xiàn)的,而不是一般的隊(duì)列, 至此,各式各樣的阻塞隊(duì)列就要派上用場(chǎng)了
二、線程池的類繼承體系在這里,有兩個(gè)核心的類: ThreadPoolExector 和ScheduledThreadPoolExecutor ,后者不僅 可以執(zhí)行某個(gè)任務(wù),還可以周期性地執(zhí)行任務(wù)。
向線程池中提交的每個(gè)任務(wù),都必須實(shí)現(xiàn) Runnable 接口,通過最上面的 Executor 接口中的 execute(Runnable command) 向線程池提交任務(wù)。
然后,在ExecutorService 中,定義了線程池的關(guān)閉接口 shutdown() ,還定義了可以有返回值 的任務(wù),也就是 Callable ,后面會(huì)詳細(xì)介紹。
三、ThreadPoolExecutor1、核心數(shù)據(jù)結(jié)構(gòu)基于線程池的實(shí)現(xiàn)原理,下面看一下ThreadPoolExector的核心數(shù)據(jù)結(jié)構(gòu)。
每一個(gè)線程是一個(gè)Worker對(duì)象。Worker是ThreadPoolExector的內(nèi)部類,核心數(shù)據(jù)結(jié)構(gòu)如下:
由定義會(huì)發(fā)現(xiàn),Worker繼承于AQS,也就是說Worker本身就是一把鎖。這把鎖有什么用處呢?用于線程池的關(guān)閉、線程執(zhí)行任務(wù)的過程中。
2、核心配置參數(shù)解釋ThreadPoolExecutor在其構(gòu)造方法中提供了幾個(gè)核心配置參數(shù),來配置不同策略的線程池。
上面的各個(gè)參數(shù),解釋如下:
1. corePoolSize:在線程池中始終維護(hù)的線程個(gè)數(shù)。
2. maxPoolSize:在corePooSize已滿、隊(duì)列也滿的情況下,擴(kuò)充線程至此值。
3. keepAliveTime/TimeUnit:maxPoolSize 中的空閑線程,銷毀所需要的時(shí)間,總線程數(shù)收縮 回corePoolSize。
4. blockingQueue:線程池所用的隊(duì)列類型。
5. threadFactory:線程創(chuàng)建工廠,可以自定義,有默認(rèn)值Executors.defaultThreadFactory()
6. RejectedExecutionHandler:corePoolSize已滿,隊(duì)列已滿,maxPoolSize 已滿,最后的拒 絕策略。
下面來看這6個(gè)配置參數(shù)在任務(wù)的提交過程中是怎么運(yùn)作的。在每次往線程池中提交任務(wù)的時(shí)候,有 如下的處理流程:
步驟一:判斷當(dāng)前線程數(shù)是否大于或等于corePoolSize。如果小于,則新建線程執(zhí)行;如果大于, 則進(jìn)入步驟二。
步驟二:判斷隊(duì)列是否已滿。如未滿,則放入;如已滿,則進(jìn)入步驟三。
步驟三:判斷當(dāng)前線程數(shù)是否大于或等于maxPoolSize。如果小于,則新建線程執(zhí)行;如果大于, 則進(jìn)入步驟四。
步驟四:根據(jù)拒絕策略,拒絕任務(wù)。
總結(jié)一下:首先判斷corePoolSize,其次判斷blockingQueue是否已滿,接著判斷maxPoolSize, 最后使用拒絕策略。 很顯然,基于這種流程,如果隊(duì)列是無界的,將永遠(yuǎn)沒有機(jī)會(huì)走到步驟三,也即maxPoolSize沒有 使用,也一定不會(huì)走到步驟四。
關(guān)鍵詞:
一、線程池的實(shí)現(xiàn)原理下圖所示為線程池的實(shí)現(xiàn)原理:調(diào)用方不斷地向線程
本文經(jīng)AI新媒體量子位(公眾號(hào)ID:QbitAI)授權(quán)轉(zhuǎn)載,轉(zhuǎn)載請(qǐng)聯(lián)系出處。
開放的網(wǎng)絡(luò)端口是網(wǎng)絡(luò)最簡(jiǎn)單的接入點(diǎn)。很多時(shí)候,我們需要在從Internet
一、背景與行業(yè)現(xiàn)狀1、數(shù)據(jù)湖理解的幾個(gè)誤區(qū)現(xiàn)在很多企業(yè)都對(duì)數(shù)據(jù)湖存
門店內(nèi),店員正熱情地為市民介紹享受補(bǔ)貼的洗烘一體機(jī)的功能,講解當(dāng)前
分時(shí)圖快速拉升意味此時(shí)存在大單買入,在大單的推動(dòng)下,股價(jià)快速地上漲
7月10日晚間,白云山(600332)發(fā)布關(guān)于“王老吉”商標(biāo)法律糾紛訴訟結(jié)
7月11日浦城縣強(qiáng)美礦業(yè)有限公司螢石出廠價(jià)格暫穩(wěn),廠家報(bào)價(jià)3000-3100元
近日,韓國(guó)愛寶樂園為大熊貓福寶招聘“一日飼養(yǎng)員助理”的公告,吸引逾
7月10日,青云科技(688316)融資買入122 82萬元,融資償還426 74萬元
今日正式入伏!中央氣象臺(tái)繼續(xù)發(fā)布高溫橙色預(yù)警:今天入伏,今年的三伏
7月10日北向資金減持32 07萬股天娛數(shù)科。近5個(gè)交易日中,獲北向資金增
7月9日,2023年“奔跑吧·少年”全國(guó)軟式棒壘球錦標(biāo)賽暨夏令營(yíng)活動(dòng)在興
它可能保留XFL的綽號(hào),它具有更長(zhǎng)的后門,并在兩個(gè)軸之間提供更大的空
任天堂的游戲機(jī)Switch今年6月在日本市場(chǎng)創(chuàng)下銷售新高,售出38萬臺(tái),同