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。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 如果你在 Java 中调用 C 语言编写的 DLL 接口,并且捕获异常失败了,那么可能存在以下几个问题: 1. Java 代码正确声明 DLL 接口:请确保 Java 代码中已经正确声明了 DLL 中的方法和数据类型。 2. Java 代码中的参数类型与 DLL 接口不匹配:请确保 Java 代码中的参数类型与 DLL 中接口的参数类型完全匹配。 3. DLL 文件缺失或路径错误:请确保 DLL 文件存在于 Java 程序的搜索路径下,并且路径正确。 4. DLL 接口异常:如果 DLL 接口内部发生了异常,那么 Java 程序可能无法正确捕获,需要在 C 代码中进行异常处理。 如果以上问题都已经排除,建议您尝试在 Java 代码中添加 try-catch 块,以便捕获任何可能发生的异常。 ### 回答2: 当Java调用C的DLL接口时,如果产生异常,通常可以通过Java异常处理机制来捕获并处理异常。但有时候可能会遇到捕获异常失败的情况,可能有以下几个原因: 首先,可能是由于C的DLL接口没有正确地抛出异常。在C语言中,异常处理不同于Java,通常使用错误码来表示异常情况。因此,当C的DLL接口没有按照Java异常机制来抛出异常时,Java是无法捕获异常的。 其次,可能是由于Java代码没有正确地调用C的DLL接口。在调用C的DLL接口时,需要遵循一定的调用规范,包括参数传递方式、返回值类型和内存管理等方面。如果Java代码没有按照规范来调用C的DLL接口,也可能导致异常无法被捕获。 还有可能是由于Java代码的异常处理机制存在问题。虽然Java异常处理机制非常强大和灵活,但如果代码逻辑不正确或异常处理代码编写有误,也有可能导致异常无法被捕获。 为了解决异常捕获失败的问题,可以尝试以下几个方法:首先,确保C的DLL接口按照Java异常机制正确地抛出异常。可以通过查看C代码和文档来确认。 其次,检查Java代码是否正确地调用了C的DLL接口。可以参考相关文档和示例代码,确保调用规范正确。 最后,检查Java代码的异常处理逻辑。确保异常处理代码的正确性,包括try-catch块的位置和异常类型的匹配等。 总之,当Java调用C的DLL接口时,捕获异常失败可能有多种原因,需要仔细检查和调试相关代码,并确保C的DLL接口按照Java异常机制正确抛出异常,Java代码正确调用C的DLL接口,并且异常处理逻辑正确无误。 ### 回答3: 在Java中调用C的dll接口时,如果捕获异常失败,可能有一些原因导致这种情况发生。 首先,如果C的dll接口没有正确地设置异常处理机制,那么即使Java代码中使用了try-catch语句,也无法捕获C代码中的异常。在这种情况下,需要先确保C代码中已经正确地设置了异常处理机制。 其次,如果C代码中的异常是通过C的错误码返回的,而不是抛出异常,那么在Java代码中捕获异常就会失败。在这种情况下,需要在Java代码中根据C的错误码进行逻辑处理。 另外,C的dll接口的异常可能是由于非法输入、内存访问错误等引起的。在Java中,如果C代码中的异常是由于访问非法的内存地址或者其他错误导致的,那么Java代码可能无法捕获这些异常。 此外,如果C代码中的异常是由于资源释放问题导致的,例如文件句柄关闭、内存泄漏等,那么在Java代码中捕获异常也可能失败。在这种情况下,需要确保C代码中的资源释放得到正确处理。 总结起来,导致Java调用C的dll接口捕获异常失败的原因可能有:C代码中正确设置异常处理机制、C代码中异常是通过错误码返回的、C代码中的异常与非法输入、内存访问错误等相关、C代码中的异常与资源释放问题相关等。为了解决这个问题,需要仔细检查C代码和Java代码中的异常处理机制,并进行相应的调整和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值