支付寶面試太太太刁鑽了!!如果把線程池 corePoolSize 設置爲 0,會出現什麼情況?

大家好,我是R哥。

最近做 Java 面試輔導,有個學員面試支付寶,遇到一個特別有意思的問題:

如果把線程池 corePoolSize 設置爲 0,會出現什麼情況?

這個問題一說出來,我都感覺有點***鑽。。

這幾年我創作小程序:Java面試庫,積累了 2700+ 的 Java 面試題,什麼***鑽的面試題沒見過?

像這樣的***鑽面試題確實少見,阿里面試官是真的卷啊。。

大廠學員都覺得會拋異常,事實上真是這樣嗎?

我們來從源碼來分析下,看看究竟!


先來回顧下線程池的工作流程:

1)如果線程池中的線程小於核心線程數 corePoolSize 時,則創建新線程直接執行任務。

2)如果線程池中的線程大於核心線程數 corePoolSize 時,則暫時把任務存儲到工作隊列 workQueue 中等待執行。

3)如果工作隊列 workQueue 也滿時:

  • 當線程數小於最大線程池數 maximumPoolSize 時,由創建新線程來處理;
  • 當線程數大於等於最大線程池數 maximumPoolSize 時,則執行拒絕策略;

更多參考我的更多 Java 多線程系列文章:https://www.javastack.cn/java/thread/


以下是 JDK 21 線程池類 ThreadPoolExecutor#execute 方法源碼:

public void execute(Runnable command) {
    // 檢查傳入的任務是否爲空,如果爲空則拋出 NullPointerException
    if (command == null)
        throw new NullPointerException();

    // 獲取當前線程池的控制狀態
    int c = ctl.get();

    // 步驟 1: 如果當前運行的線程數少於核心線程數
    if (workerCountOf(c) < corePoolSize) {
        // 嘗試添加一個新的工作線程來執行提交的任務
        // 如果添加成功,則直接返回
        if (addWorker(command, true))
            return;
        
        // 再次獲取線程池的控制狀態,以應對併發變化
        c = ctl.get();
    }

    // 步驟 2
    // 步驟 2.1: 如果線程池處於運行狀態並且任務能夠成功加入隊列
    if (isRunning(c) && workQueue.offer(command)) {
        // 再次檢查線程池的狀態,確認線程池仍然處於運行狀態
        int recheck = ctl.get();
        
        // 2.2 如果線程池不再運行,並且任務能夠從隊列中移除,則拒絕任務
        if (!isRunning(recheck) && remove(command))
            reject(command);
        
        // 2.3 如果當前線程池沒有運行的線程
        else if (workerCountOf(recheck) == 0)
            // 嘗試添加一個新的非核心工作線程(false 表示非核心線程)
            addWorker(null, false);
    }
    // 步驟 3
    else {
        // 3.1 嘗試添加一個新的非核心工作線程來執行任務
        if (!addWorker(command, false))
            // 3.2 如果添加失敗,說明線程池已關閉或達到飽和狀態,因此拒絕任務
            reject(command);
    }
}

我檢查了 JDK 8 和 JDK 17 兩個主版本源碼,這塊的處理邏輯也是一樣的。

從源碼可以看到,如果往線程池提交任務的時候,當 corePoolSize = 0 時,代碼正常情況下會執行到步驟2。

以下三步是關鍵步驟:

步驟 2.1:

此時,如果線程池處於運行狀態,並且任務能夠成功加入隊列,說明線程池不爲空,線程正常執行任務。

步驟 2.3:

此時,如果當前線程池沒有運行的線程,則嘗試添加一個新的非核心工作線程,即任務會先進入隊列排隊再由線程獲取任務執行。

步驟 3.1:

此時,說明隊列滿了無法加入任務,嘗試添加一個新的非核心工作線程來執行任務,如果添加失敗,說明線程池已關閉或達到飽和狀態,因此拒絕任務。

擴展知識點:

這個邏輯在 JDK 6 之前略有不同,在 JDK 6 之前,當 corePoolSize = 0 的時候,先將這個任務放到阻塞隊列中,只有等隊列滿了才創建線程來執行,而 JDK 6+ 是直接創建一個非核心線程,再放在隊列中來執行,很顯示,JDK 6 這個優化動作減小了內存溢出的可能性。

光說 JDK 6 和 JDK 8 這兩個版本,對線程池的重構就很大,現在主流的版本都是 JDK 8+,這個瞭解一下就好。


這道題可以說是八股文之王了,我工作這麼多年,面試過這麼多人,也沒有見過這道題。

對於阿里這樣的大廠,可能會遇到奇奇怪怪的問題,不會很正常,說說自己的想法,或許不會太減分。但如果你恰好看到了我的公衆號,又學會了這道題,那下次有面試官問起,那就是加分題了,面試官也會對你眼前一亮。

像這樣的面試八股文,我的小程序「Java面試庫」還有許多,比如:

  • 爲什麼阿里不讓用 Executors 創建線程池?
  • 線程池中的線程拋出了異常,如何處理?
  • ......

共 2700+,都是平時我面試別人,或者學員面試覆盤積累下來的真題,不要在網上找亂七八糟的面試題了,浪費時間還容易被誤導。

最後,推薦一波我的「面試輔導訓練營」,有在看機會的,離職的、迷茫的,都可以加入我們的「面試輔導訓練營」,大廠導師 1 v 1 輔導,幫你全面提升面試綜合實力,少走很多彎路,最大化提升職場收益。

版權聲明: 本文系公衆號 "Java技術棧" 原創,轉載、引用本文內容請註明出處,抄襲、洗稿一律投訴侵權,後果自負,並保留追究其法律責任的權利。

更多文章推薦:

1.Spring Boot 3.x 教程,太全了!

2.2,000+ 道 Java面試題及答案整理(2024最新版)

3.免費獲取 IDEA 激活碼的 7 種方式(2024最新版)

覺得不錯,別忘了隨手點贊+轉發哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章