3

已经写了很多关于一般异常的智慧以及特别是在 Java 中使用已检查与未检查异常的文章,但我有兴趣看到对将线程终止作为默认策略而不是应用程序终止的决定的辩护它在 C++ 中的方式。这个选择对我来说似乎非常危险:程序员没有计划的某些情况会导致程序的某些部分在记录堆栈跟踪后死掉,但其余的程序士兵却坚决地坚持下去,会出什么问题?我的直觉和经验表明,这里很多事情都可能出错,默认策略是那种只能由有特定理由选择它的人专门选择的东西,那又如何?这个策略的好处是什么,却有这么大的坏处?我是否高估了风险?

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

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

4

3 回答 3

1

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

  1. 一般来说,如果应用程序的一个组件由于数据库重启或某些文件被替换等任何原因(暂时或永久)失败,那么让应用程序失败是一个坏主意。例如,如果我引入了一种新型的交易系统并且出现了一些问题,它不应该关闭我的应用程序。

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

根据您对异常的担忧,通常所有应用程序都有一个健康监控系统,用于监控它们的健康状况,如 CPU/磁盘/RAM 使用情况或日志中的错误等,并相应地发出警报。

我希望这能解决您的困惑。

于 2013-01-24T03:22:19.780 回答
1

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

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

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

环境因素是单线程程序很可能是该语言最初开发时的常态,因此默认行为伪装成正确的行为。多核架构的兴起和线程池使用的增加使威胁更广泛地暴露出来,而常用的方法(例如使用不可变对象)只能解决这个问题(提示:ConcurrentMap 可能不如您安全认为是)。到目前为止,我的经验是,否认这种风险的人相对于他们代码的实际安全要求还不够偏执,但我希望被证明是错误的。

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

于 2013-01-30T04:55:57.893 回答
0

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

基于 GUI 的应用程序,它会很好地显示错误消息并能够更有效地处理错误 - 例如,我们可以提交带有一些附加信息的缺陷报告。

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

这里有一些有用的注意事项

于 2013-01-24T05:26:14.367 回答