Java中默认的未捕获信号处理程序策略的基本原理是什么?

时间:2013-01-24 03:03:14

标签: java exception

关于一般异常的智慧以及特别是在Java中使用已检查与未检查异常的问题已经写了很多,但是我很有兴趣看到为使线程终止成为默认策略的决定的辩护应用程序终止它在C ++中的方式。这个选择对我来说似乎非常危险:程序员没有随机计划的一些条件会导致程序的某些部分在记录堆栈跟踪后死亡,但其余的程序士兵坚决开启,可能会出错?我的直觉和经验表明,很多事情都可能在这里出错,默认政策是那种只能由有特定理由选择它的人专门选择的东西,那么这个策略的优点是什么呢?这样一个看似很大的缺点?我是否高估了风险?

编辑:基于到目前为止的答案,我觉得我需要更加专注于我对我所看到的危险的描述;我在谈论使用多个线程(例如在线程池中)的应用程序的情况,以更新共享状态。我认识到这个策略不会给单线程应用程序带来问题。

EDIT2:您可以通过解释为什么不推荐使用Thread.stop()方法(在此处找到http://docs.oracle.com/javase/7/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html)来了解语言维护者对这些风险的认识。当线程由于未捕获的异常而意外死亡时,会出现完全相同的问题。他们必须设计JVM,以便在线程死亡时自动解锁所有监视器,这似乎是一个糟糕的实现选择;在监视器被锁定时线程死亡应该表明整个程序应该死掉,因为在某些共享状态下,替代方案几乎肯定是内部不一致。

3 个答案:

答案 0 :(得分:1)

@BD,不确定您的体验对此有何看法,因为您没有在此解释过。但是,这是我作为开发人员所经历的:

  1. 通常,如果其中一个组件由于DB重新启动或某个文件被替换等任何原因而导致(暂时或永久)失败,则使应用程序失败是一个坏主意。例如,如果我在系统中引入了一种新类型的交易并且出现了一些问题,它就不应该关闭我的应用程序。

  2. 像Web /应用程序服务器这样的应用程序应该能够继续工作并响应用户,即使它的任何部署都抛出了任何奇怪的异常。

  3. 根据您对异常的担心,通常所有应用程序都有一个运行状况监视系统,可以监视其健康状况,如CPU /磁盘/ RAM使用情况或日志中的错误等,并相应地触发警报。

    我希望这可以解决你的困惑。

答案 1 :(得分:1)

通过与同事讨论这个问题,并回顾到目前为止收到的答案,我在这里形成了一个假设,并希望得到一些反馈。

我怀疑将此行为作为默认行为的决定源于定义语言早期发展及其早期环境的哲学。

作为原始哲学的一部分,程序员/设计者应该使用已检查的异常,并且语言强制执行由方法调用发出的已检查异常(即已在方法定义中声明)必须在调用方法,或者由它声明“正式”将责任传递给更高级别的呼叫者。常见做法已远离使用已检查的异常,更不用说实践中最常出现的异常之一NullPointerException未经检查。因此,程序员现在必须假设任何方法调用都可以生成未经检查的异常,并且这样做的必然结果是,在并发上下文中更新共享数据的任何代码都必须为这些更新实现事务语义才能完全正确。我的经验是,大多数开发人员并不真正理解这一点,即使他们确实理解多线程开发的基础知识,例如在使用同步管理关键部分时避免死锁。默认的未捕获异常处理程序行为通过屏蔽其影响来加剧问题:在C ++中,如果未捕获的异常会导致共享状态损坏,因为程序已经死了无关紧要,但在Java中,程序将继续跛行尽管它很可能不再正常运行,但最好的还是可以。

环境因素是单线程程序可能是首次开发语言时的常态,因此默认行为伪装成正确的行为。多核架构的兴起和线程池使用的增加更广泛地暴露了威胁,并且通常应用的方法(例如使用不可变对象)只能到目前为止才能解决它(一些提示:ConcurrentMap可能不像你那么安全认为是)。到目前为止,我的经验是拒绝这种风险的人相对于他们的代码的实际安全要求并不是很偏执,但我希望被证明是错误的。

我怀疑修改未捕获的异常处理程序以终止程序应该是大多数开发组织所需的标准过程;至少应该为已知根据传入输入更新共享状态的线程池完成此操作。

答案 2 :(得分:0)

正常(没有GUI,没有容器)应用程序退出未捕获的异常 - 默认行为很好 - 与您想要的一样。

基于GUI的应用程序,很高兴显示错误消息并能够更有效地处理错误 - 例如,我们可以提交缺陷报告以及其他一些信息。

通过提供特定于线程的异常处理程序(可能包括应用程序退出),可以完全改变行为。

Here是一些有用的注释