共计 2564 个字符,预计需要花费 7 分钟才能阅读完成。
当一个线程在执行过程中抛出了异样,并且没有进行 try..catch,那么这个线程就会终止运行。
在 Thread 类中,提供了两个能够设置线程未捕捉异样的全局处理器,咱们能够在处理器里做一些工作,例如将异样信息发送到近程服务器。
尽管这能够捕捉到线程中的异样,然而并不能阻止线程进行运行。因而该在线程 run 办法里 try..catch 的,还是要好好的进行 try..catch。
从 Thread 类源代码中能够看到这 2 个变量:
private volatile UncaughtExceptionHandler uncaughtExceptionHandler;
private static volatile UncaughtExceptionHandler defaultUncaughtExceptionHandler;
须要留神到区别,defaultUncaughtExceptionHandler 是动态的,咱们能够调用此办法设置所有线程对象的异样处理器,而 uncaughtExceptionHandler 则是针对单个线程对象的异样处理器。
uncaughtExceptionHandler 优先级高于 defaultUncaughtExceptionHandler。
Thread 类提供了这 2 个变量的 setter/getter:
public static void setDefaultUncaughtExceptionHandler(UncaughtExceptionHandler eh) {SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("setDefaultUncaughtExceptionHandler")
);
}
defaultUncaughtExceptionHandler = eh;
}
public static UncaughtExceptionHandler getDefaultUncaughtExceptionHandler(){return defaultUncaughtExceptionHandler;}
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
return uncaughtExceptionHandler != null ?
uncaughtExceptionHandler : group;
}
public void setUncaughtExceptionHandler(UncaughtExceptionHandler eh) {checkAccess();
uncaughtExceptionHandler = eh;
}
能够看到,getUncaughtExceptionHandler() 中进行了判断,当 uncaughtExceptionHandler 为 null 时返回 group。
咱们来看下 UncaughtExceptionHandler 接口是怎么申明的:
@FunctionalInterface
public interface UncaughtExceptionHandler {void uncaughtException(Thread t, Throwable e);
}
咱们只须要实现 UncaughtExceptionHandler 接口,重写 uncaughtException 办法即可进行异样解决。
那么 JVM 是怎么检测到线程产生异样,并将异样散发到处理器的呢?
对于这块代码,JDK 源码中看不到是如何解决的,可能须要翻阅 hotspot 源码,不过 Thread 类中提供了一个 dispatchUncaughtException 办法,将异样回调到了 uncaughtExceptionHandler 中去解决。
private void dispatchUncaughtException(Throwable e) {getUncaughtExceptionHandler().uncaughtException(this, e);
}
很显著,dispatchUncaughtException 应该就是提供给 hotspot 进行 JNI 回调的。
而对于 defaultUncaughtExceptionHandler 的调用,猜想应该是在 hotspot 中间接实现了。
接下来咱们用示例来演示一下异样处理器的成果。
示例:
Thread thread = new Thread(() -> {System.out.println("run before");
System.out.println("runing");
if(1 == 1) {throw new IllegalStateException("exception");
}
System.out.println("run after");
});
thread.setUncaughtExceptionHandler((t, e) -> System.out.println("捕捉异样," + t.getName() + "," + e.getMessage()));
Thread.setDefaultUncaughtExceptionHandler((t, e) -> System.out.println("Default 捕捉异样," + t.getName() + "," + e.getMessage()));
thread.start();
输入:
run before
runing
捕捉异样,Thread-0,exception
能够看出,尽管两个异样处理器都有设置,并且 defaultUncaughtExceptionHandler 是最初设置的,不过起效的是 uncaughtExceptionHandler。
能够将 thread.setUncaughtExceptionHandler(…); 正文掉:
输入:
run before
runing
Default 捕捉异样,Thread-0,exception
正文后,defaultUncaughtExceptionHandler 起效了,证实了 uncaughtExceptionHandler 优先级高于 defaultUncaughtExceptionHandler。