首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

Java 線程池程式執行完畢但 JVM 不退出的排查與修正

     編輯:程式設計綜合問答

使用 ExecutorService 線程池時,主線程提交任務後呼叫 shutdown() 與 awaitTermination(),理應等待所有任務完成並正常退出。但若主線程邏輯錯誤,導致 shutdown() 未被呼叫或提前結束,JVM 會因非守護執行緒仍在運作而拒絕退出(Eclipse 控制台紅點不變灰)。

問題程式碼分析

public static void main(String[] args) {
    int thread = 0;
    ExecutorService pool = Executors.newFixedThreadPool(15);
    for (int i = 666; i <= 888; i++) {
        for (int j = 0; j < 19; j++) {
            pool.execute(new MyClass(i, j));
        }
    }
    thread++;  // 只執行一次!
    if (thread >= 15) {  // 永遠不會成立
        pool.shutdown();
        // ... awaitTermination ...
        System.exit(0);
    }
}

核心錯誤:thread++ 與 if 判斷在迴圈外部,且只執行一次,thread 永遠為 1,永不滿足 >=15,導致 shutdown() 從未被呼叫,線程池持續運行,JVM 不退出。

正確關閉流程

ExecutorService pool = Executors.newFixedThreadPool(15);
// 提交所有任務
for (int i = 666; i <= 888; i++) {
    for (int j = 0; j < 19; j++) {
        pool.execute(new MyClass(i, j));
    }
}

// 1. 關閉線程池,不再接受新任務
pool.shutdown();

try {
    // 2. 等待現有任務完成,設定超時時間
    if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
        // 3. 超時則強制關閉正在執行的任務
        pool.shutdownNow();
    }
} catch (InterruptedException e) {
    pool.shutdownNow();
    Thread.currentThread().interrupt(); // 保留中斷狀態
}

// 4. 正常退出(非必要,main 結束即退出)
// System.exit(0);

關鍵點總結

  • shutdown() 必須在提交完所有任務後呼叫一次,而非在迴圈或條件判斷中。
  • awaitTermination() 會阻塞主線程,直到所有任務完成或超時。
  • 若任務可能長時間阻塞(如 I/O、鎖),需在任務內部定期檢查 Thread.interrupted() 並拋出 InterruptedException,配合 shutdownNow() 的中斷機制實現真正停止。
  • 主線程結束即代表 JVM 退出(若無其他非守護執行緒),System.exit(0) 通常多餘。

進階建議

生產環境建議使用 ThreadPoolExecutor 直接構建,自訂 ThreadFactory 設定執行緒名稱、RejectedExecutionHandler 處理拒絕策略,並搭配監控指標(佇列長度、活躍執行緒數)觀察線程池健康狀態。

正確管理線程池生命週期,是 Java 併發程式穩定運行的基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved