JVM 如何处理未捕获异常

栏目: Java · 发布时间: 5年前

内容简介:继之前的文章详解JVM如何处理异常,今天再次发布一篇比较关联的文章,如题目可知,今天聊一聊在JVM中线程遇到未捕获异常的问题,其中涉及到线程如何处理未捕获异常和一些内容介绍。未捕获异常指的是我们在方法体中没有使用try-catch捕获的异常,比如下面的例子上面的代码很有可能发生如下情况

继之前的文章详解JVM如何处理异常,今天再次发布一篇比较关联的文章,如题目可知,今天聊一聊在JVM中线程遇到未捕获异常的问题,其中涉及到线程如何处理未捕获异常和一些内容介绍。

什么是未捕获异常

未捕获异常指的是我们在方法体中没有使用try-catch捕获的异常,比如下面的例子

private static void testUncaughtException(String arg) {
    try {
        System.out.println(1 / arg.length());
    } catch (ArithmeticException e) {
        e.printStackTrace();
    }
}

上面的代码很有可能发生如下情况

  • 如果方法参数arg传递null,会出现NullPointerException
  • 如果参数arg传递内容为空的字符串(“”),会出现ArithmeticException

对于上面的问题,我们不难发现

  • 上面可能出现的NullPointerException和ArithmeticException都属于Unchecked Exceptions
  • 而ArithmeticException被我们人为try-catch捕获了,它不符合本文对于未捕获异常的定义
  • NullPointerException 由于我们没有catch住,就变成了我们要聊的未捕获异常
  • 另外,未捕获异常实际是Unchecked Exceptions的子集

UncaughtExceptionHandler 是什么

void uncaughtException(Thread t, Throwable e);
Thread.setUncaughtExceptionHandler
Thread.setDefaultUncaughtExceptionHandler

ThreadGroup 是什么

  • ThreadGroup 是线程的集合
  • ThreadGroup 也可以包含子ThreadGroup
  • 除了初始的ThreadGroup 之外,每个ThreadGroup都有一个父 ThreadGroup
  • ThreadGroup 自身实现了Thread.UncaughtExceptionHandler,用来相应处理其内部的线程和ThreadGroup发生未捕获异常。

未捕获异常处理者 设置指南

JVM 如何处理未捕获异常

线程发生了未捕获异常,JVM怎么处理

分发Throwable实例

当线程A中出现了未捕获异常时,JVM会调用线程A的 dispatchUncaughtException(Throwable) 方法

/**
 * Dispatch an uncaught exception to the handler. This method is
 * intended to be called only by the JVM.
 */
private void dispatchUncaughtException(Throwable e) {
    getUncaughtExceptionHandler().uncaughtException(this, e);
}

获取未捕获异常处理者

  • 每个线程会有一个变量(uncaughtExceptionHandler)来保存未捕获异常的处理者
  • 在线程需要确定Throwable分发目标的处理者时,优先获取当前线程中uncaughtExceptionHandler变量
  • 如果出问题线程的uncaughtExceptionHandler为null(即没有显式设置异常处理者),则使用自己所在的ThreadGroup来作为未捕获异常处理者。
/**
 * Returns the handler invoked when this thread abruptly terminates
 * due to an uncaught exception. If this thread has not had an
 * uncaught exception handler explicitly set then this thread's
 * <tt>ThreadGroup</tt> object is returned, unless this thread
 * has terminated, in which case <tt>null</tt> is returned.
 * @since 1.5
 * @return the uncaught exception handler for this thread
 */
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
    return uncaughtExceptionHandler != null ?
        uncaughtExceptionHandler : group;
}

如果Throwable分发给ThreadGroup

Thread.getDefaultUncaughtExceptionHandler()
/**
     * Called by the Java Virtual Machine when a thread in this
     * thread group stops because of an uncaught exception, and the thread
     * does not have a specific {@link Thread.UncaughtExceptionHandler}
     * installed.
     * <p>
     * The <code>uncaughtException</code> method of
     * <code>ThreadGroup</code> does the following:
     * <ul>
     * <li>If this thread group has a parent thread group, the
     *     <code>uncaughtException</code> method of that parent is called
     *     with the same two arguments.
     * <li>Otherwise, this method checks to see if there is a
     *     {@linkplain Thread#getDefaultUncaughtExceptionHandler default
     *     uncaught exception handler} installed, and if so, its
     *     <code>uncaughtException</code> method is called with the same
     *     two arguments.
     * <li>Otherwise, this method determines if the <code>Throwable</code>
     *     argument is an instance of {@link ThreadDeath}. If so, nothing
     *     special is done. Otherwise, a message containing the
     *     thread's name, as returned from the thread's {@link
     *     Thread#getName getName} method, and a stack backtrace,
     *     using the <code>Throwable</code>'s {@link
     *     Throwable#printStackTrace printStackTrace} method, is
     *     printed to the {@linkplain System#err standard error stream}.
     * </ul>
     * <p>
     * Applications can override this method in subclasses of
     * <code>ThreadGroup</code> to provide alternative handling of
     * uncaught exceptions.
     *
     * @param   t   the thread that is about to exit.
     * @param   e   the uncaught exception.
     * @since   JDK1.0
     */
    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);
            }
        }
    }

将上面的处理流程做成图的形式,就是下图所示

JVM 如何处理未捕获异常

注:上述图片来自 https://www.javamex.com/tutorials/exceptions/exceptions_uncaught_handler.shtml

Questions

初始的ThreadGroup是什么

上面提到了初始的ThreadGroup没有父ThreadGroup,是主线程所在的ThreadGroup么?

这个问题,我们可以通过这样一段代码验证

private static void dumpThreadGroups() {
    ThreadGroup threadGroup = Thread.currentThread().getThreadGroup();
    while(threadGroup != null) {
        System.out.println("dumpThreadGroups threadGroup=" + threadGroup.getName());
        threadGroup = threadGroup.getParent();
    }
}

执行该方法对应的输出是

dumpThreadGroups threadGroup=main
dumpThreadGroups threadGroup=system

因此我们可以发现,初始的ThreadGroup是一个叫做system的ThreadGroup,而不是main ThreadGroup

setDefaultUncaughtExceptionHandler 设置的一定会被调用到么

这其实是一个很好的问题,答案是不一定会被调用,因为可能存在以下的情况

  • 出问题的线程设置了对应的UncaughtExcpetionHandler,优先响应分发到这个Handler
  • 出问题的线程所在的ThreadGroup包括其祖先ThreadGroup 重写了uncaughtException 也可能造成线程默认的Handler无法被调用
  • 出问题的线程重写了dispatchUncaughtException 可能性较小
  • 出问题的线程重写了getUncaughtExceptionHandler 可能性较小

参考声明


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

理想主义者

理想主义者

[美] 贾斯汀·彼得斯 / 程静、柳筠 / 重庆出版社 / 2018-5-15 / 49.80元

2013年1月11日,年仅26岁的黑客亚伦·斯沃茨自杀身亡,此事在美国引起轩然大波。这不仅是因为在互联网领域,斯沃茨是一个可以与比尔·盖茨、马克·扎克伯格、理查德·斯托曼等齐名的人,更是因为此事揭露了传统世界与互联网世界的规则冲突。 在互联网思维下,信息是明码标价的商品。各种利益方用技术竖起了一道道藩篱,将支付不起费用但渴望用知识改变命运的人隔绝在外。于是,一大批希望改变这种模式的“理想主义......一起来看看 《理想主义者》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码