我正在使用获得许可的API,该API具有从具有有限数量许可证的许可证服务器获取/释放许可证对象的方法。在我的应用程序开始时,我调用该方法获取许可证,但我想确保即使我的程序突然终止/崩溃(例外,SIGTERM等)也会释放它。关闭钩子是解决此问题的最佳方法吗?
答案 0 :(得分:8)
@thedan对于硬JVM崩溃是正确的。如果JVM很难崩溃或者它获得了SIGKILL,那么在退出之前它就没有机会运行任何东西。在这种情况下,您无法用Java来解决这个问题。 (但其他语言的情况也一样......)
但是,如果JVM按顺序关闭所有非dameon线程结束,调用System.exit(),获取SIGINT等,那么JVM将尝试运行关闭钩子。有关Q&A页面和javadocs中Java关闭挂钩机制的更多信息。
finally
方法也是一种选择,但仅在有问题的线程在JVM退出之前终止时才有效。如果调用System.exit()
或者JVM被信号终止,则不会发生这种情况。关机挂钩适用于更多情况。
(在我看来,finally
实际上是在单个线程而不是整个应用程序上执行clean。但是如果你的应用程序只包含一个线程......或者它有一个主线程是负责有序关闭...然后finally
可以用于应用程序清理。)
真正的解决方案是配置许可API,以便许可证管理器可以检测使用许可证的应用程序实例何时消失而不释放它。这是否可行取决于许可证管理器。
答案 1 :(得分:3)
如果程序因JVM崩溃而终止,则不能依赖任何被调用的东西。
如果程序是通过不涉及JVM的异常终止的,那么你应该能够将所有东西都包装在try / catch / finally块中。 finally代码块中的任何代码都将保证在代码退出之前运行。
答案 2 :(得分:2)
对于例外情况,您可以将main
的正文包裹在try/catch/block
中。要处理SIGTERM
信号,您可以add a shutdown hook。但是,不能保证为SIGKILL
等信号触发关闭挂钩。
来自Java doc:
在极少数情况下,虚拟机可能会中止,即停止 在没有干净地关闭的情况下跑步。这发生在虚拟时 机器在外部终止,例如使用
SIGKILL
信号 在Unix上或在Microsoft Windows上调用TerminateProcess
。虚拟 例如,如果本机方法出错,机器也可能会中止 破坏内部数据结构或尝试访问 不存在的记忆。 如果虚拟机中止则无法保证 可以判断是否会运行任何关机挂钩。
答案 3 :(得分:1)
你通过从不调用System.exit()来实现这一点。 在main()中,您可以使用
创建“最后一道防线” try {
startApp();
} catch (Exception ex) {
// do some logging
} finally {
releaseLicense();
}