版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_30038111/article/details/83003719
线程在执行单元中不允许抛出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
中。