支付寶面試太太太刁鑽了!!如果把執行緒池 corePoolSize 設定為 0,會出現什麼情況?

Java技术栈發表於2024-03-29

大家好,我是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最新版)

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

相關文章