使用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实例设置未捕获异常处理者

  • 也可以通过 静态方法 Thread.setDefaultUncaughtExceptionHandler 设置所有Thread实例的未捕获异常处理者

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
 * ThreadGroup object is returned, unless this thread
 * has terminated, in which case null is returned.
 * @since 1.5
 * @return the uncaught exception handler for this thread
 */
public UncaughtExceptionHandler getUncaughtExceptionHandler() {
 return uncaughtExceptionHandler != null ?
 uncaughtExceptionHandler : group;
}

如果Throwable分发给ThreadGroup

  • ThreadGroup会尝试转给它的父ThreadGroup(如果存在的话)

  • 如果上面没有找到对应的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.
 * 

 * The uncaughtException method of  * ThreadGroup does the following:  * 

     * 
  • If this thread group has a parent thread group, the  * uncaughtException method of that parent is called  * with the same two arguments.  * 
  • Otherwise, this method checks to see if there is a  * {@linkplain Thread#getDefaultUncaughtExceptionHandler default  * uncaught exception handler} installed, and if so, its  * uncaughtException method is called with the same  * two arguments.  * 
  • Otherwise, this method determines if the Throwable  * 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 Throwable's {@link  * Throwable#printStackTrace printStackTrace} method, is  * printed to the {@linkplain System#err standard error stream}.  * 
 * 

 * Applications can override this method in subclasses of  * ThreadGroup 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 可能性较小

看完上述内容是否对您有帮助呢?如果还想对相关知识有进一步的了解或阅读更多相关文章,请关注创新互联行业资讯频道,感谢您对创新互联的支持。


分享名称:使用JVM怎么处理未捕获的异常
当前地址:http://myzitong.com/article/jcdjdi.html