6

我正在使用许可的 API,它具有从具有有限数量许可证的许可证服务器获取/释放许可证对象的方法。在我的应用程序开始时,我调用该方法来获取许可证,但我想确保即使我的程序突然终止/崩溃(异常、SIGTERM 等)也能释放它。关闭挂钩是解决此问题的最佳方法吗?

4

4 回答 4

7

@thedan 关于硬 JVM 崩溃是正确的。如果 JVM 严重崩溃或收到 SIGKILL,它在退出之前将没有机会运行任何东西。在这种情况下,您无法在 Java 中解决此问题。(但其他语言的情况也一样......)

但是,如果 JVM 有序关闭以响应所有非 dameon 线程结束、调用 System.exit()、获取 SIGINT 等,那么 JVM 将尝试运行关闭挂钩。在问答页面和javadocs中有更多关于 Java 的关闭挂钩机制的信息。

finally方法也是一种选择,但仅在相关线程在 JVM 退出之前终止时才有效。如果System.exit()被调用或 JVM 被信号终止,则不会发生这种情况。关闭挂钩适用于更多情况。

(在我看来,finally实际上是在单个线程而不是整个应用程序上执行清理。但是,如果您的应用程序仅包含一个线程......或者它有一个负责有序关闭的主线程......那么finally可以达到应用程序清理的目的。)


真正的解决方案是配置许可 API,以便许可管理器可以检测到使用许可的应用程序实例何时消失而无需释放它。这是否可能取决于许可证管理器。

于 2012-12-06T23:19:05.630 回答
3

如果程序因 JVM 崩溃而终止,则您不能依赖任何被调用的内容。

如果程序因不涉及 JVM 的异常而终止,您应该能够将所有内容包装在 try/catch/finally 块中。finally 块中的任何代码都将保证在您的代码退出之前运行。

于 2012-12-06T23:09:34.900 回答
2

对于例外情况,您可以将 的主体包裹maintry/catch/block. 为了处理SIGTERM信号,您可以添加一个关闭挂钩。但是,不能保证关闭挂钩会被触发,例如SIGKILL.

来自Java 文档

在极少数情况下,虚拟机可能会中止,即停止运行而没有完全关闭。当虚拟机在外部终止时会发生这种情况,例如SIGKILLUnix 上的信号或TerminateProcessMicrosoft Windows 上的调用。如果本地方法出错,例如破坏内部数据结构或尝试访问不存在的内存,虚拟机也可能中止。如果虚拟机中止,则无法保证是否会运行任何关闭挂钩。

于 2012-12-06T23:14:24.143 回答
1

您可以通过从不调用 Sytem.exit() 来实现这一点。在 main() 中,您创建了“最后一道防线”

 try {
    startApp();
 } catch (Exception ex) {
      // do some logging
 } finally {
    releaseLicense();
 }
于 2012-12-06T23:17:46.580 回答