本文共 3125 字,大约阅读时间需要 10 分钟。
线程在执行单元中不允许抛出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 : ArithmeticExceptionAssign , Thread name : nullPoint , Exception : NullPointerExceptionjava.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
中。
转载地址:http://qvcsn.baihongyu.com/