如下代碼,在 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: