UncaughtExceptionHandler處理執行緒中的執行時異常
阿新 • • 發佈:2018-11-08
執行緒在執行單元中不允許丟擲checked
異常,而且執行緒執行在自己的上下文中,派生它的執行緒無法直接獲得它執行中出現的異常資訊。對此,Java
為我們提供了UncaughtExceptionHandler
介面,當執行緒在執行過程中出現異常時,會回撥UncaughtExceptionHandler
介面,從而得知是哪個執行緒在執行時出錯。UncaughtExceptionHandler
介面在Thread
中定義。
在Thread
類中,關於處理執行時異常的API
有四個:
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh)
為某個特定執行緒指定UncaughtExceptionHandler
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh)
設定全域性的UncaughtExceptionHandler
public UncaughtExceptionHandler getUncaughtExceptionHandler()
獲取特定執行緒的UncaughtExceptionHandler
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()
獲取全域性的UncaughtExceptionHandler
UncaughtExceptionHandler 簡單使用
// 全域性異常處理 Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { System.out.printf("Default , Thread name : %s , Exception : %s\n", t.getName(), e.getClass().getSimpleName()); e.printStackTrace(); } }); Thread arithmetic = new Thread(() -> { throw new ArithmeticException(); }, "arithmetic"); arithmetic.start(); // ---------------------------------------------- Thread nullPoint = new Thread(() -> { throw new NullPointerException(); }, "nullPoint"); // 指定異常處理 nullPoint.setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { public void uncaughtException(Thread t, Throwable e) { System.out.printf("Assign , Thread name : %s , Exception : %s\n", t.getName(), e.getClass().getSimpleName()); e.printStackTrace(); } }); nullPoint.start();
輸出結果:
Default , Thread name : arithmetic , Exception : ArithmeticException
Assign , Thread name : nullPoint , Exception : NullPointerException
java.lang.ArithmeticException
at com.p7.demo.UncaughtExceptionHandlerTest.lambda$0(UncaughtExceptionHandlerTest.java:24)
at java.lang.Thread.run(Thread.java:748)
java.lang.NullPointerException
at com.p7.demo.UncaughtExceptionHandlerTest.lambda$1(UncaughtExceptionHandlerTest.java:32)
at java.lang.Thread.run(Thread.java:748)
UncaughtExceptionHandler 原始碼分析
/* The group of this thread,每建立一個Thread物件時,都會呼叫Thread的init方法,這個方法初始化了當前執行緒的執行緒組 */
private ThreadGroup group;
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
getUncaughtExceptionHandler
方法首先判斷當前執行緒是否設定了handler
,如果有則使用自己的uncaughtException
方法,否則就在所屬的ThreadGroup
中獲取,ThreadGroup
實現了UncaughtExceptionHandler
。
private final ThreadGroup parent;
public void uncaughtException(Thread t, Throwable e) {
if (parent != null) {
parent.uncaughtException(t, e);
} else {
Thread.UncaughtExceptionHandler ueh =
Thread.getDefaultUncaughtExceptionHandler();
if (ueh != null) {
ueh.uncaughtException(t, e);
} else if (!(e instanceof ThreadDeath)) {
System.err.print("Exception in thread \""
+ t.getName() + "\" ");
e.printStackTrace(System.err);
}
}
}
該ThreadGroup
如果有父ThreadGroup
,則直接呼叫父Group
的uncaughtException
;如果設定了全域性預設的UncaughtExceptionHandler
,呼叫全域性的uncaughtException
;如果沒有父ThreadGroup
且沒有全域性預設的UncaughtExceptionHandler
,直接將異常的堆疊資訊定向到System.err
中。