美團面試官:核心線程數(shù)為0時,線程池如何執(zhí)行?
線程池是 Java 中用于提升程序執(zhí)行效率的主要手段,也是并發(fā)編程中的核心實現(xiàn)技術(shù),并且它也被廣泛的應(yīng)用在日常項目的開發(fā)之中。那問題來了,如果把線程池中的核心線程數(shù)設(shè)置為 0 時,線程池是如何執(zhí)行的?
要回答這個問題,我們首先要了解在正常情況下,線程池的執(zhí)行流程,也就是說當(dāng)有一個任務(wù)來了之后,線程池是如何運行的?
1.線程池的執(zhí)行流程
正常情況下(核心線程數(shù)不為 0 的情況下)線程池的執(zhí)行流程如下:
- 判斷核心線程數(shù):先判斷當(dāng)前工作線程數(shù)是否大于核心線程數(shù),如果結(jié)果為 false,則新建線程并執(zhí)行任務(wù)。
- 判斷任務(wù)隊列:如果大于核心線程數(shù),則判斷任務(wù)隊列是否已滿?如果結(jié)果為 false,則把任務(wù)添加到任務(wù)隊列中等待線程執(zhí)行。
- 判斷最大線程數(shù):如果任務(wù)隊列已滿,則判斷當(dāng)前線程數(shù)量是否超過最大線程數(shù)?如果結(jié)果為 false,則新建線程執(zhí)行此任務(wù)。
- 判斷是否要執(zhí)行拒絕策略:如果超過最大線程數(shù),則將執(zhí)行線程池的拒絕策略。
如下圖所示:
圖片
核心線程數(shù) VS 最大線程數(shù)
核心線程數(shù)(corePoolSize)和最大線程數(shù)(maximumPoolSize)都是線程池中的兩個重要參數(shù),其中:
- 核心線程數(shù)定義了線程池中最小線程數(shù)量,即使這些線程處于空閑狀態(tài),也不會被銷毀。
- 最大線程數(shù)定義了線程池中允許的最大線程數(shù)量,最大線程數(shù)等于核心線程數(shù) + 臨時線程數(shù),最大線程數(shù)主要是提供了一種機制來應(yīng)對突發(fā)的高并發(fā)請求,當(dāng)有大量任務(wù)的時候,可以創(chuàng)建線程數(shù)量的上線。
PS:在線程池的使用過程中,最大線程數(shù)必須大于等于核心線程數(shù),否則程序執(zhí)行會報錯。
2.核心線程為0的執(zhí)行流程
那么問題來了,按照線程池的正常執(zhí)行流程來看,如果核心線程數(shù)為 0 的話,那么當(dāng)任務(wù)來了之后會判斷當(dāng)前工作的線程數(shù)不大于核心線程數(shù),那也就不會創(chuàng)建線程執(zhí)行任務(wù)了,會將任務(wù)放到隊列。
但這個結(jié)果又很滑稽,有任務(wù)來了線程池竟然不執(zhí)行,而是先放到任務(wù)隊列中,這好像有比較奇怪,這就好比你開了一個快遞店,當(dāng)有快遞來了之后,你想的不是如何派送,而是直接把它丟到倉庫一樣滑稽,這會讓等快遞的人很著急,所以,我們需要驗證一下線程池的執(zhí)行是否如我們猜想的那般,驗證代碼如下:
// 線程池核心線程數(shù)設(shè)置為 0
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
0, 10, 1, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10));
// 給線程池添加任務(wù)
threadPoolExecutor.execute(() -> {
System.out.println("www.javacn.site");
});最終程序的執(zhí)行結(jié)果如下:
圖片
咦,結(jié)果怎么不符合我們的預(yù)期呢?為什么任務(wù)來了之后,沒有將任務(wù)放到任務(wù)隊列而是直接執(zhí)行了呢?
雖然程序執(zhí)行結(jié)果符合正常邏輯,但又和我們了解的線程池執(zhí)行理論相違背,這是什么原因呢?
查看線程池的執(zhí)行源碼
帶著這個疑問,我們查看了線程池的執(zhí)行源碼發(fā)現(xiàn),線程池的執(zhí)行過程遠(yuǎn)比我們想想的復(fù)雜,線程池核心源碼如下:
圖片
從上面源碼可以看出,當(dāng)我們將任務(wù)添加到隊列的時候,線程池會判斷工作的線程數(shù)是否為 0,也就是上面圈出來的那行代碼,如果當(dāng)前工作線程為 0 的話,會創(chuàng)建線程執(zhí)行任務(wù)。哦,原來如此,這樣,就能將理論和實踐對應(yīng)上了。
也就是說,當(dāng)核心線程數(shù)為 0 時,當(dāng)來了一個任務(wù)之后,會先將任務(wù)添加到任務(wù)隊列,同時也會判斷當(dāng)前工作的線程數(shù)是否為 0,如果為 0,則會創(chuàng)建線程來執(zhí)行線程池的任務(wù),這就是正確的線程池執(zhí)行流程,同時也是面試官想要的答案。


































