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

JUnit 單元測試多執行緒失效根因與兩種修正方案

     編輯:Java 綜合教學

現象

測試方法啟動子執行緒發送郵件,主執行緒結束後程序直接退出,子執行緒任務未完成、郵件未發出,無任何異常拋出。

根因:JUnit TestRunner 設計

public static void main(String[] args) {
    TestResult r = new TestRunner().start(args);
    if (!r.wasSuccessful()) System.exit(1);
    System.exit(0);   // 主執行緒結束即強制 JVM 退出
}

System.exit() 會終結整個 JVM,子執行緒來不及執行即被強制殺掉。

驗證代碼

@Test public void testThread() {
    new Thread(() -> {
        for (int i=0; i<10000; i++)
            System.out.println("i=" + i + " time=" + System.currentTimeMillis());
    }).start();
    // 無等待,主執行緒直接結束
}

輸出僅到 ~750 循環即中斷。

解決方案

方案一:主執行緒睡眠(簡單但不精確)

Thread.sleep(5000);  // 盲目等待,時間難把控

方案二:CountDownLatch 同步(推薦)

@Test public void testThread() throws InterruptedException {
    CountDownLatch latch = new CountDownLatch(1);
    new Thread(() -> {
        try {
            for (int i=0; i<10000; i++) { /* work */ }
        } finally {
            latch.countDown();  // 任務完成釋放
        }
    }).start();
    latch.await(5, TimeUnit.MINUTES);  // 阻塞主執行緒,最多等 5 分鐘
}
  • 子執行緒正常結束 → countDown() → 主執行緒繼續。
  • 超時釋放 → 避免無限等待導致 CI 卡死。

進階:自定義 Runner 支援多執行緒

社區有現成 ConcurrentTestRunner,原理為重寫 run() 收集所有子執行緒 join(),有興趣可自行搜尋接入。

總結

JUnit 4/5 預設不支援測試方法內啟動的守護執行緒存活超過主執行緒,務必使用 CountDownLatch、CompletableFuture 或 Thread.join() 顯式同步。

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