Java 引发未处理的异常后线程被卡住
我有一个无头运行的应用程序,需要能够将问题通知管理员。我构建了一个电子邮件通知框架供其使用,基本上,如果抛出并捕获了异常,根据代码中的区域和异常的严重程度,它可能会被传递到警报通知框架,该框架会触发一封电子邮件,将堆栈跟踪和其他调试信息发送给列出的管理员 这很管用 在部署之前,我对它进行了测试。我的一个测试是从代码中的一个随机点抛出一个未处理的异常——模拟一个潜在的严重运行时问题,其中抛出的异常是我们没有预料到的 例如,以下是我插入测试未处理异常的方法:Java 引发未处理的异常后线程被卡住,java,exception,Java,Exception,我有一个无头运行的应用程序,需要能够将问题通知管理员。我构建了一个电子邮件通知框架供其使用,基本上,如果抛出并捕获了异常,根据代码中的区域和异常的严重程度,它可能会被传递到警报通知框架,该框架会触发一封电子邮件,将堆栈跟踪和其他调试信息发送给列出的管理员 这很管用 在部署之前,我对它进行了测试。我的一个测试是从代码中的一个随机点抛出一个未处理的异常——模拟一个潜在的严重运行时问题,其中抛出的异常是我们没有预料到的 例如,以下是我插入测试未处理异常的方法: /** * Closes connec
/**
* Closes connection.
*/
public void closeConnection() {
if (true)
throw new NullPointerException("Test unexpected exception NPE");
LOG.info("Closing SFTP connection");
getSftpChannel().exit();
getSession().disconnect();
LOG.debug("SFTP Connection closed");
}
代码运行,当它遇到这个未处理的异常时,程序会硬锁(因为会引发异常,并且sftp连接线程从未关闭,所以它会保持jvm打开,直到连接超时)
我原以为它会使JVM崩溃,或者将其传递给它的调用者,调用者最终会冒泡到警报系统
在这个场景中,我假设这个NPE会抛出这个异常,不由它的调用者或调用者的调用者处理,等等,所以它应该冒泡到main(),然后使JVM崩溃,因为即使是main也不会捕获异常或NPE
问题
:这里发生了什么?我如何确保这样的场景不会在生产中出现?我是不是在main()中有一个巨大的catch-all-catch子句,并让它catch-allException
,以便处理每个异常
为清晰起见进行编辑:
问题或多或少是--为什么未在方法签名中显式抛出、也未由调用方处理的未处理异常不会使JVM崩溃?
使用finally块确保连接关闭
public void closeConnection() {
try {
if (true)
throw new NullPointerException("Test unexpected exception NPE");
} finally {
LOG.info("Closing SFTP connection");
getSftpChannel().exit();
getSession().disconnect();
LOG.debug("SFTP Connection closed");
}
}
回答您的问题:为什么没有在方法签名中显式抛出、也没有由调用方处理的未处理异常不会使JVM崩溃 假设此代码在线程中运行,原因是,除非在线程类或线程实例上设置了
UnhandledExceptionHandler
,否则“main”线程组是默认的UnhandledExceptionHandler
。默认情况下,线程组通过将堆栈跟踪记录到system.out来处理未处理的异常,线程“死亡”,JVM不会崩溃
您可能想考虑实现一个使用您的电子邮件框架通知这些故障的非HealthExcel处理程序。
正如其他海报所建议的那样,代码应该在finally块中清理频道和会话等资源。也许我应该更清楚一点——示例中的NPE仅用于测试目的。。。代码显然不仅仅是无缘无故地抛出新的NPE-P——因此,将整个代码库放在try/finally块中是没有意义的。将对closeConnection的调用放在finally块中是没有意义的。问题是,如果在代码库中的任何地方抛出任何未处理的异常,我就会得到这个挂起的JVM。不仅仅是在这个示例方法中,也不仅仅是在示例NPE中。问题更多的是更少的--
为什么没有在方法签名中显式抛出,也没有由调用方处理的未处理异常不会使JVM崩溃?
为什么您认为它应该崩溃?