当一个线程在执行过程中抛出了异常,并且没有进行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。

最新文章

  1. css样式之background详解(格子效果)
  2. Mac 下 PostgreSQL 的安装与使用
  3. CSS 伪类 (Pseudo-classes)
  4. poj 2187 Beauty Contest (凸包暴力求最远点对+旋转卡壳)
  5. 为什么选择 Yeoman 及 Yeoman 的安装
  6. XAML(2) - 依赖属性
  7. 【Leetcode】Evaluate Reverse Polish Notation JAVA
  8. ZOJ 3596Digit Number(BFS+DP)
  9. wcf+linq to sql中关联查询返回数据问题
  10. sdut 2847 Monitor (思维题)
  11. FFMPEG + SDL音频播放分析
  12. Storm系列(一)集群的安装配置
  13. CentOS 6.7安装配置Ansible
  14. 【转】Win7下VS2010中配置Opencv2.4.4的方法(32位和64位都有效)(亲测成功)
  15. 1294 - Positive Negative Sign(规律)
  16. Swift - 动态添加删除TableView的单元格(以及内部元件)
  17. mysql的架构
  18. python学习之路四(类和对象1)
  19. 菲菲更名宝贝 得意非凡版 v1.9 免费绿色版
  20. 远程桌面连接问题,ping服务器ip无法连接主机。

热门文章

  1. 【Java】idea同时运行多个一样的类
  2. OKR之剑(理念篇)01—— OKR带给我们的改变
  3. Exchange 2019中的Unified Messaging(UM)
  4. Vue3 封装 Element Plus Menu 无限级菜单组件
  5. Java SE 枚举,注解,增强for循环
  6. Python数据科学手册-Pandas:数据取值与选择
  7. Django ORM 事务和查询优化
  8. nginx日志参数及含义
  9. Docker目录/var/lib/docker/containers文件太大
  10. shell脚本中执行source命令不生效的解决办法