在Thread中有异常处理器相关的方法
在ThreadGroup中也有相关的异常处理方法

示例

未检查异常

对于未检查异常,将会直接宕掉,主线程则继续运行,程序会继续运行
在主线程中能不能捕获呢?
我们简单粗暴一点,直接全部包到try catch中
你会发现,然而并没有什么卵用,主线程中的try catch并不会得到什么信息,跟原来的结果还是一样的,线程直接宕掉

已检查异常

对于已检查的异常,run方法本身是不支持抛出的,上面代码中,想要throws,IDE提示异常,从run方法可以看得出来
run方法本身是不支持throws的(签名中没有throws)
所以怎么办?
既然是已检查异常,肯定是要处理的,既然不能丢出去,就只有一个办法了,那就是自己捕获,放置在try catch中

小结

在run方法中是不能够抛出异常的,如果是已检查的异常,那么必须进行try catch
对于未检查的异常,如果没有进行处理,一旦抛出线程将会宕掉,而且在主线程中并不能捕获到这个异常
难道对于未检查的异常也都是try catch吗?(当然,这是一种方式)
还有没有其他解决方案?

异常处理器

在Java线程的run方法中,对于未检查异常,借助于异常处理器进行处理的
字面意思,直接理解为处理异常的方法,那么如何配置这个处理异常的方法呢?如何设置,又是如何调用?
UncaughtExceptionHandler,是Thread的内部接口(1.8中已经设置为函数式接口)
Thread内部有两个变量,用于记录异常处理器
对于两个set方法,没有什么特别的,主要就是设置这两个内部变量
对于getUncaughtExceptionHandler方法,如果当前非空,那么返回当前,否则,将返回当前线程组,很显然,ThreadGroup实现了Thread.UncaughtExceptionHandler
对于getDefaultUncaughtExceptionHandler,这是简单的返回内部变量
此时我们大致了解到了这几个方法,内部有两个UncaughtExceptionHandler异常处理器,分别都有getter和setter方法
setter方法都是直接设置
getDefaultUncaughtExceptionHandler是直接获取
getUncaughtExceptionHandler如果非空那么直接获取,否则将会返回当前线程组,当前线程组也实现了Thread.UncaughtExceptionHandler,内部实现了方法public void uncaughtException(Thread t, Throwable e)
换句话说,线程组内部实现了一个线程处理器

两个处理器含义

我们看到了表面的样子,但是这两个内部变量到底干嘛的?
对于defaultUncaughtExceptionHandler,表示的是应用程序默认的,应用程序默认的,也就是整个程序使用的,可以看得到,对于他的getter和setter以及自身,都是static修饰的
对于uncaughtExceptionHandler,属于实例方法,也就是说每个线程可以拥有一个
简言之:每个线程都可以有一个uncaughtExceptionHandler,整个应用可以有一个defaultUncaughtExceptionHandler
全局和个体的关系,就如同我们平时见到的其他概念一样,如果单独设置了,那么就使用自己的,如果没有设置就走全局的
既可以单独设置,又可以全局设置(没有设置的才会走全局),既可以保障灵活性,有能够对于那些没设置的提供统一配置,比如统一将异常信息写入文件等,也有诸多应用场景与好处

异常处理器处理逻辑

当异常发生时,JVM会调用异常分发处理器,也就是借助于getUncaughtExceptionHandler方法,获取异常处理器,然后执行他的uncaughtException方法
第一个参数就是当前线程this,第二个参数就是异常对象
看注释:JVM调用
 
所以关键点在于getUncaughtExceptionHandler返回什么异常处理器,我们再回过头来看下源代码
如果已经设置,那么将会直接返回;
如果没有设置,将会返回当前线程组(前面说了ThreadGroup实现了Thread.UncaughtExceptionHandler)
当调用ThreadGroup的uncaughtException方法时,如上图下半部分
如果他的父线程组重写了uncaughtException方法,那么将会调用他的父线程组的方法,如果父亲节点没有重写,爷爷节点重写了将会调用爷爷的,以此类推
但是如果所有的祖先线程组都没有重写呢?很显然,所有的方法代码都是上面这样子的(上图下半部分),将会递归到顶级线程组,然后不满足parent,然后走到else,这中间什么有意义的事情都没有做
在else中,会首先获取应用默认的异常处理器,如果仍旧是没有设置
不好意思,直接转到system.err了

代码示例

从上面的示例可以看得出来,尽管仍就出现了异常,我们能够进行信息获取与感知,不会直接宕掉了
如果先start,然后在设置异常处理器会发生什么?
可以看得到,线程仍旧是直接宕掉,异常处理器无效,所以setUncaughtExceptionHandler方法必须在start方法前调用!

总结

在Thread中的run方法,不能够抛出异常,只能进行捕获
  • 对于已检查异常,必须捕获
  • 对于未检查异常,你也可以进行try catch,但是代码始终包裹在try中,真的好吗?
  • 还另外提供了异常处理器机制用于处理未检查异常
有两种异常处理器:
线程自身的处理器和全局的异常处理器
  1. 如果设置了异常处理器uncaughtExceptionHandler,那么将会使用这个
  2. 如果没设置,将会在祖先线程组中查找第一个重写了uncaughtException的线程组,然后调用他的uncaughtException方法
  3. 如果都没有重写,那么使用应用默认的全局异常处理器defaultUncaughtExceptionHandler
  4. 如果还是没有设置,直接标准错误打印信息
如果想要设置自己的异常处理器,可以通过对应的setter方法进行设置,如果想要设置全局的可以调用静态方法进行设置
异常处理器Thread.UncaughtExceptionHandler是一个函数式接口,所以后续,你可以使用Lambda表达式直接编写,大大减少了工作量

异常处理器详解 Java多线程异常处理机制 多线程中篇(四)的更多相关文章

  1. 详解java动态代理机制以及使用场景

    详解java动态代理机制以及使用场景 https://blog.csdn.net/u011784767/article/details/78281384 深入理解java动态代理的实现机制 https ...

  2. Java Garbage Collection基础详解------Java 垃圾回收机制技术详解

    最近还是在找工作,在面试某移动互联网公司之前认为自己对Java的GC机制已经相当了解,其他面试官问的时候也不存在问题,直到那天该公司一个做搜索的面试官问了我GC的问题,具体就是:老年代使用的是哪中垃圾 ...

  3. 详解Java动态代理机制

    之前介绍的反射和注解都是Java中的动态特性,还有即将介绍的动态代理也是Java中的一个动态特性.这些动态特性使得我们的程序很灵活.动态代理是面向AOP编程的基础.通过动态代理,我们可以在运行时动态创 ...

  4. 详解Java动态代理机制(二)----cglib实现动态代理

    上篇文章的结尾我们介绍了普通的jdk实现动态代理的主要不足在于:它只能代理实现了接口的类,如果一个类没有继承于任何的接口,那么就不能代理该类,原因是我们动态生成的所有代理类都必须继承Proxy这个类, ...

  5. 详解java中CAS机制所导致的问题以及解决——内存顺序冲突

    [CAS机制] 指的是CompareAndSwap或CompareAndSet,是一个原子操作,实现此机制的原子类记录着当前值的在内存中存储的偏移地址,将内存中的真实值V与旧的预期值A做比较,如果不一 ...

  6. java基础(十五)----- Java 最全异常详解 ——Java高级开发必须懂的

    本文将详解java中的异常和异常处理机制 异常简介 什么是异常? 程序运行时,发生的不被期望的事件,它阻止了程序按照程序员的预期正常执行,这就是异常. Java异常的分类和类结构图 1.Java中的所 ...

  7. Java -- 异常的捕获及处理 -- Java的异常处理机制

    7.1.4 Java的异常处理机制 在整个Java的异常处理中,实际上也是按照面向对象的方式进行处理,处理的步骤如下: ⑴ : 一旦产生异常,则首先会产生一个异常类的实例化对象. ⑵ : 在try语句 ...

  8. “全栈2019”Java异常第十五章:异常链详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...

  9. 详解Java GC的工作原理+Minor GC、FullGC

    详解Java GC的工作原理+Minor GC.FullGC 引用地址:http://www.blogjava.net/ldwblog/archive/2013/07/24/401919.html J ...

随机推荐

  1. docker-maven-plugin插件设置Docker的buildArgs

    docker-maven-plugin是spotify出品的一款针对spring boot项目的docker插件,可将spring boot项目打包到docker镜像中. 如果在编译docker镜像时 ...

  2. 关于docker jenkins启动时失败的问题处理

    最近在做持续集成,然后使用docker 运行jenkins docker run -d  -p 8088:8080 -p 50000:50000 -v /home/docker/jenkins_hom ...

  3. Http_4个新的http状态码:428、429、431、511

    1.428 Precondition Required (要求先决条件) 先决条件是客户端发送 HTTP 请求时,必须要满足的一些预设条件.一个好的例子就是 If-None-Match 头,经常用在 ...

  4. 神经网络_线性神经网络 2 (Nerual Network_Linear Nerual Network 2)

    1 LMS 学习规则 1.1 LMS学习规则定义 MSE=(1/Q)*Σe2k=(1/Q)*Σ(tk-ak)2,k=1,2,...,Q 式中:Q是训练样本:t(k)是神经元的期望输出:a(k)是神经元 ...

  5. MySql的编译安装

    一 前期准备 1 cmake包,要求2.8以上版本 https://cmake.org/download/ 2 boost库包 boost Boost库是一个可移植.提供源代码的C++库,作为标准库的 ...

  6. 字符串----hiho字符串(尺取法)

    注意:这道题的解法和最短摘要一样,都是采用尺取法解决问题,注意这儿题目要求恰好包含,也就是说这个hiho字符串必须包含2个'h'.1个'i'和1个'o'.一个不能多,一个也不能少. import ja ...

  7. [Swift]LeetCode609. 在系统中查找重复文件 | Find Duplicate File in System

    Given a list of directory info including directory path, and all the files with contents in this dir ...

  8. iOS模拟器使用

    在iOS开发过程中一直都是使用模拟器进行调试,在模拟器上有很多不适应的地方,但是其实在模拟器上也有很多其他的功能,在本文中主要对模拟器的一些基本功能进行总结一下. 1 首先,我们了解一下模拟器中常用的 ...

  9. djang-异步——定时操作

    django本身是一个同步框架,flask也是,所以要把它变成异步操作的话还得专门设置一下 我的这个系统呢是windows系统,python3.7的 所以有的库是不可以兼容的 ,然后到时候会稍微修改一 ...

  10. 【Spark篇】---Spark中资源和任务调度源码分析与资源配置参数应用

    一.前述 Spark中资源调度是一个非常核心的模块,尤其对于我们提交参数来说,需要具体到某些配置,所以提交配置的参数于源码一一对应,掌握此节对于Spark在任务执行过程中的资源分配会更上一层楼.由于源 ...