Java线程中处理运行时异常(UncaughtExceptionHandler)

线程在执行单元中不允许抛出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,则直接调用父GroupuncaughtException;如果设置了全局默认的UncaughtExceptionHandler,调用全局的uncaughtException;如果没有父ThreadGroup且没有全局默认的UncaughtExceptionHandler,直接将异常的堆栈信息定向到System.err中。

你可能感兴趣的:(Java,并发编程)