開(kāi)篇!詳解Java線程池

由于工作中基本都是CRUD操作,對(duì)線程池不常用,所以一直沒(méi)去具體了解過(guò)其底層原理,但是在工作、健身之余一直有一顆躁動(dòng)的心,想在技術(shù)上浸淫的更深入一點(diǎn)(其實(shí)lz就是想技術(shù)好點(diǎn),工資高點(diǎn)),所以這幾天就查看了線程池的底層源碼。另外開(kāi)個(gè)公眾號(hào)記錄一下筆記,練練文筆,豈不美哉!

話不多說(shuō),開(kāi)始!

Java線程池詳解

目前Java線程池的創(chuàng)建JUC提供了四種方便的快捷方法,利用Executors工具類直接創(chuàng)建,如下圖

Java線程池詳解

方便快捷,那為什么還要研究底層呢?(之后說(shuō)明)

然而它們的底層實(shí)現(xiàn)又是什么,線程池又是怎么進(jìn)行擴(kuò)容的呢?稍等,一一說(shuō)明。

先來(lái)看下底層實(shí)現(xiàn)

Java線程池詳解
Java線程池詳解
Java線程池詳解

可以看到,底層都是有ThreadPoolExecutor類實(shí)現(xiàn)的和阻塞隊(duì)列實(shí)現(xiàn)的,而且Executors.newScheduledThreadPool()一直點(diǎn)下去也是ThreadPoolExecutor類。

接下來(lái)查看一下ThreadPoolExecutor類,其底層究竟是什么?七大參數(shù)又是什么?

Java線程池詳解

七個(gè)參數(shù),分別是corePoolSize,maximumPoolSize,keepAliveTime,unit,workQueue,threadFactory和handler。

(1)corePoolSize:就是線程池中的常駐核心線程數(shù)。

(2)maximumPoolSize:線程池能容納同時(shí)執(zhí)行的最大線程數(shù)。

(3)keepAliveTime:空閑線程的最大存活時(shí)間。

(4)unit:keepAliveTime參數(shù)的時(shí)間單位

(5)workQueue:任務(wù)隊(duì)列,被提交但是尚未被執(zhí)行的任務(wù)將存放在此。

(6)threadFactory:生成線程池中工作線程的工廠。

(7)handler:拒絕策略,當(dāng)任務(wù)隊(duì)列已滿并且當(dāng)前工作線程數(shù)量等于maximumPoolSize執(zhí)行的策略。

線程池工作流程:

1.創(chuàng)建線程池

2.提交任務(wù),線程池會(huì)進(jìn)行判斷

(1)如果正在運(yùn)行的線程數(shù)量小于corePoolSize,則新建一個(gè)線程執(zhí)行任務(wù)

(2)如果正在運(yùn)行的線程數(shù)量等于corePoolSize,則任務(wù)進(jìn)入等待隊(duì)列

(3)如果正在運(yùn)行的線程數(shù)量大于等于corePoolSize并且小于maximumPoolSize,則會(huì)進(jìn)行擴(kuò)容,新建一個(gè)線程執(zhí)行任務(wù)。

(4)如果隊(duì)列已滿并且正在運(yùn)行的線程數(shù)量等于maximumPoolSize,則會(huì)執(zhí)行拒絕策略。

3.如果當(dāng)前運(yùn)行的線程數(shù)量大于corePoolSize,并且有部分線程在keepAliveTime時(shí)間內(nèi)無(wú)事可做,就會(huì)執(zhí)行線程銷毀,直至線程數(shù)量等于corePoolSize為止。

可能上述解釋有點(diǎn)抽象,下面就是一個(gè)比喻,一看就明:

銀行網(wǎng)點(diǎn)大家都知道,通常營(yíng)業(yè)的時(shí)候會(huì)有幾個(gè)正在服務(wù)的窗口,也會(huì)有幾個(gè)停止服務(wù)的窗口(就是沒(méi)有漂亮小姐姐的那種,懂了吧?。矔?huì)有侯客區(qū)(幾排冷冰冰的鐵椅),銀行網(wǎng)點(diǎn)就是線程池,而正在值班的窗口就是corePoolSize,全部窗口數(shù)量就是maximumPoolSize,侯客區(qū)就是任務(wù)隊(duì)列。去銀行辦理業(yè)務(wù)一般是如下流程,如果正在值班的窗口有空閑的,就馬上辦理業(yè)務(wù),如果值班窗口都在辦理業(yè)務(wù),則進(jìn)入侯客區(qū)進(jìn)行等待。如果值班窗口都在辦理業(yè)務(wù)并且侯客區(qū)已滿,銀行就會(huì)進(jìn)行將停止服務(wù)的窗口開(kāi)通(稱為“加班窗口”)。如果全部窗口都在辦理業(yè)務(wù),侯客區(qū)已滿,大堂經(jīng)理就會(huì)進(jìn)行拒絕客戶的操作,這就是拒絕策略。如果辦業(yè)務(wù)人數(shù)持續(xù)減少,如果加班窗口已經(jīng)不辦業(yè)務(wù)了,過(guò)了一段時(shí)間(也即是keepAliveTime)之后就會(huì)將加班窗口撤掉,直到所有加班窗口都被撤掉。

那什么又是拒絕策略呢?

Java線程池詳解

JUC包提供了四種拒絕策略,分別是

(1)AbortPolicy:默認(rèn)的拒絕策略,會(huì)直接拋異常

例如我手寫(xiě)了一個(gè)線程池,corePoolSize是2,maximumPoolSize是5,任務(wù)隊(duì)列容量為3,那么線程池最多可以同時(shí)提交8個(gè)任務(wù)。但我提交了10個(gè)任務(wù)。所以直接拋異常。

Java線程池詳解
Java線程池詳解

(2)CallerRunsPolicy:調(diào)用者策略,將任務(wù)返回給調(diào)用者,利用調(diào)用者線程執(zhí)行提交給線程池中的任務(wù)。

Java線程池詳解
Java線程池詳解

直接返回給main線程執(zhí)行。

(3)DiscardOldestPolicy:將隊(duì)列中等待時(shí)間最長(zhǎng)的任務(wù)直接扔掉

Java線程池詳解
Java線程池詳解

(4)DiscardPolicy:直接扔掉線程

Java線程池詳解
Java線程池詳解

OK,上述就是我理解的線程池(僅作為筆記記錄),如果有不同見(jiàn)解的,歡迎指正。

為什么不建議直接用JUC提供的Executors工具類直接創(chuàng)建線程池呢,因?yàn)橛眠@個(gè)工具類直接創(chuàng)建的話底層的阻塞隊(duì)列容量是Integer.MAX_VALUE,在高并發(fā)的時(shí)候容易任務(wù)堆積,造成OOM的情況。(不是我說(shuō)的,這是馬云爸爸的團(tuán)隊(duì)說(shuō)的)

Java線程池詳解

=======================================================

我是Liusy,一個(gè)喜歡健身的程序猿。

歡迎關(guān)注【Liusy01】,一起交流Java技術(shù)及健身,獲取更多干貨。

最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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