Java线程未捕获异常处理 UncaughtExceptionHandler
当一个线程在执行过程中抛出了异常,并且没有进行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。
Java线程未捕获异常处理 UncaughtExceptionHandler的更多相关文章
- Java & Android未捕获异常处理机制
一.背景 无论是Java还是Android项目,往往都会用到多线程.不管是主线程还是子线程,在运行过程中,都有可能出现未捕获异常.未捕获异常中含有详细的异常信息堆栈,可以很方便的去帮助我们排查问题. ...
- Android 之 应用未捕获异常处理
最近开发一款低功耗蓝牙通讯的 Android 应用,安装使用时多次出现“ 抱歉,xxx已停止 ”.现在安装Android系统的手机版本和设备千差万别,在模拟器上运行良好的程序安装到某款手机上说不定就出 ...
- 自己定义Application的未捕获异常处理
近期由于工作原因.进行Android应用开发时发现应用在出现类似空指针等异常时,抛出未被捕获的异常.Android系统有默认的未捕获异常处理器,默认行为是结束对应的线程,但并不会直接退出程序,并且在应 ...
- Java线程中的异常处理
对于对线程,当主线程中有子线程运行出现异常时,主线程是不能捕获到该异常的,子线程会直接退出,不会记录任何日志. 解决: 1.子线程中try catch. 2.设置线程的未捕获异常处理器,Uncaugh ...
- JAVA线程池ScheduledExecutorService周期性地执行任务 与单个Thread周期性执行任务的异常处理
本文记录: 1,使用ScheduledExecutorService的 scheduleAtFixedRate 方法执行周期性任务的过程,讨论了在任务周期执行过程中出现了异常,会导致周期任务失败. 2 ...
- Java子线程中的异常处理(通用)
在普通的单线程程序中,捕获异常只需要通过try ... catch ... finally ...代码块就可以了.那么,在并发情况下,比如在父线程中启动了子线程,如何正确捕获子线程中的异常,从而进行相 ...
- java线程异常处理方法
工作中常发现有些程序发生异常但却没有错误日志,原因就是一些开发线程异常处理错误,导致程序报错但异常信息打印到堆栈上,不好在生产环境中定位问题. 在java多线程程序中,所有线程都不允许抛出未捕获的ch ...
- JAVA 线程中的异常捕获
在java多线程程序中,所有线程都不允许抛出未捕获的checked exception(比如sleep时的InterruptedException),也就是说各个线程需要自己把自己的checked e ...
- 捕获Java线程池执行任务抛出的异常
捕获Java线程池执行任务抛出的异常Java中线程执行的任务接口java.lang.Runnable 要求不抛出Checked异常, public interface Runnable { publi ...
随机推荐
- linux scsi相关的一些学习笔记
最近看scsi相关处理的一些备忘,比较零碎,仅作参考. 先从最显而易见的打印入手: [0:0:0:0] disk ATA INTEL SSDSC2BX20 0150 - [0:0:1:0] dis ...
- docker的volume和bind mount究竟有什么区别?
不知道你在使用docker的时候,有没有注意到volume mount和bind mount的使用? 进一步说,他们之间的区别到底是什么? 接下来的内容,我们就为你揭开他们的神秘面纱. 相同之处 首先 ...
- 给博客添加个充电按钮(仿B站)
今天我准备吧B站的充电按钮移植到本博客,开始- 上代码: HTML <html> <head> <link href="./space.8.f69f7d6f8f ...
- 线性代数 | Jordan 标准型的笔记
内容概述: 把方阵 A 的特征多项式 \(c(λ)=|λE-A|\) 展开成 \(c(λ)=\sum_ia_i\lambda^i\) 的形式,然后使用神乎其技的证明,得到 \(c(A)=O\),特征多 ...
- rtmp/rtsp/hls公网测试地址
相信大家在调试播放器的时候,都有这样的困惑,很难找到合适的公有测试源,以下是大牛直播整理的真正可用的直播地址源. 其中,rtmp和rtsp的url,用https://github.com/daniul ...
- Java 将Excel转为UOS
以.uos为后缀的文件,表示Uniform Office Spreadsheet文件,是一种国产的办公文件格式,该格式以统一办公格式(UOF)创建,使用XML和压缩保存电子表格.既有的Excel表格文 ...
- 认识RocketMQ4.x架构设计
消息模型 单体的消息模型 RocketMQ消息模型跟其他的消息队列一样 都是 producer - > topic->consumer producer 生产消息 也就是发送者 topic ...
- AlertManager 何时报警
转载自:https://www.qikqiak.com/post/alertmanager-when-alert/ 在使用 Prometheus 进行监控的时候,通过 AlertManager 来进行 ...
- 解决zeal离线文档下载慢问题
zeal简介 编程过程中难免会遇到不会用的关键字和方法,对我而言,在windows下,我使用Zeal这个软件进行离线文档查询. 问题 但是,在软件中下载DocSet(文档)会出现下载慢,或者下载不了的 ...
- 自定义mapping与常见参数
PUT test { "mappings": { "dynamic": true, "properties": { "firstn ...