捕獲子線程中的異常

如下代碼,在 main 線程中,是無法捕獲子線程的異常的。
catch 子句中的代碼不會被執行。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class NaiveExceptionHandling {
    public static void main(String[] args) {
        ExecutorService exec = Executors.newCachedThreadPool();
        try {
            exec.execute(() -> {
                throw new RuntimeException();
            });
        } catch (RuntimeException e) {
            System.out.println("this msg will not de printed");
        }
        exec.shutdown();
    }
}

輸出:

Exception in thread "pool-1-thread-1" java.lang.RuntimeException
	at NaiveExceptionHandling.lambda$main$0(NaiveExceptionHandling.java:9)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
	at java.lang.Thread.run(Thread.java:748)

Process finished with exit code 0

改造:

  • newCachedThreadPool 創建線程池時指定自定義的 ThreadFactory
  • 自定義的 ThreadFactory 工廠在生產線程時,爲其設置 UncaughtExceptionHandler 異常處理
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;

public class NaiveExceptionHandling {

    public static void main(String[] args) {
        ExecutorService exec2 = Executors.newCachedThreadPool(new HandleThreadFactory());
        exec2.execute(() -> {
            throw new RuntimeException();
        });
        exec2.shutdown();
    }
}

class HandleThreadFactory implements ThreadFactory {
    @Override
    public Thread newThread(Runnable r) {
        System.out.println("create thread t");
        Thread t = new Thread(r);
        System.out.println("set uncaughtException for t");
        t.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
            @Override
            public void uncaughtException(Thread t, Throwable e) {
                System.out.println("caught " + e);
            }
        });
        return t;
    }

}

輸出:

create thread t
set uncaughtException for t
caught java.lang.RuntimeException

那麼主線程爲什麼不能捕獲子線程的異常呢?知乎上有如下解釋:

  • 因爲execute方法會立即返回,所以早就運行出try塊了,實際上主線程已經提前結束。
  • 設計的主要初衷是線程運行是互相獨立的,可以理解主線程也是一種普通的線程即可。如果線程之間異常互相干擾,那麼1000個線程,一個線程掛了,其它線程跟着遭殃,這是不合理的。

ref:

  1. https://blog.csdn.net/wild46cat/article/details/80808555
  2. 《Java 編程思想(第4版)》 P672
  3. https://www.zhihu.com/question/67790293
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章