我有一种情况,当用户通知操作系统(在我的情况下只有 Windows)关闭时,我想执行某些任务。
我尝试过使用java shutdown hooks。我面临的问题是,当我使用
System.exit(0);
退出程序时,关闭挂钩会被调用,但当我直接关闭计算机时,它们不会被调用。
这是我用于关闭挂钩的代码-
Runtime.getRuntime().addShutdownHook(new JVMShutdownHook()); //in main method
//within the main java class
private static class JVMShutdownHook extends Thread {
@Override
public void run() {
//perform tasks
}
}
有什么方法可以与操作系统交互(我假设有一些本机代码),以便它允许我的程序正常退出?
任何帮助将不胜感激。
ShutdownHooks
确实无法通过关闭 Windows 来工作。我认为这是 Java 的一个 bug,并于上周打开了一个 BugReport。然而,它尚未发布。
2008 年有一个旧的错误报告:当用户注销时,Runtime#addShutdownHook 在 Windows Vista 上不起作用。 Windows 7 也会出现同样的问题。该票证已被 java.com 关闭,但没有得到令人满意的响应。
Windows 通过关闭给应用程序一些时间来正常终止。延迟由注册表项
WaitToKillApplication
定义。我希望 java 程序使用此延迟来执行钩子(如果设置了 Runtime.runFinalizersOnExit()
,则最终确定)。
让我们看看 Oracle 是否将其识别为错误...
您必须编写本机方法。两个用于添加和删除关闭钩子,另一个将充当钩子的回调方法,从中调用 java 代码。 您的钩子必须监听操作系统关闭消息,并在发生这种情况时调用您的回调。这就是许多阻止 Windows 进入睡眠模式或运行屏幕保护程序的应用程序的工作方式。
在这里查看一些关于 JNI 的信息
http://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html
关于钩子在这里
https://msdn.microsoft.com/en-us/library/windows/desktop/ms644960%28v=vs.85%29.aspx
几年前我必须使用 JDK 11 为 Windows 部署的应用程序实现此功能。
关于链接的答案,您可以为此上下文创建更适合的实现。
我最初在那里发布了我的答案,可用于解决这两个问题,但它有不同的上下文,例如显示不应该在我的实现中使用的 UI 元素(正如我所指出的那样)。由于在这种情况下没有这样的要求,我认为我描述的是最简单的实现和一个合适的“足够”的 API 来使用。
即使它们是内部API的一部分,您也可以直接使用相应的类,因为它们没有被强封装。
详情请参阅JEP403:
删除、封装或修改任何关键内容不是目标 标准替代品尚未实现的 JDK 内部 API 存在。这意味着 sun.misc.Unsafe 将保持可用。
链接的 JEP 上有以下说明:
JDK 9 中未封装关键的内部 API
JDK 9 中没有封装关键的内部 API,因为 JDK 8 中不存在受支持的替换,此处列出。
- sun.misc.{信号,SignalHandler}
而且所有当前支持的(截至撰写本文时)LTS JDK 都支持在
TERM
上引发 WM_QUERYENDSESSION
信号的功能。遗憾的是我无法链接文档,但我可以链接源代码参考:
OpenJDK 8,
OpenJDK 11,
OpenJDK 17,
OpenJDK 21。
基于上述内容,您可以创建一个更简单的实现,而无需使用反射(以及因此的异常处理):
Runtime.getRuntime().addShutdownHook(/* Add your implementation here! */);
SignalHandler handler = (Signal sig) -> {
System.exit(0);
};
Signal.handle(new Signal("TERM"), handler);
一旦启动关闭序列,您的关闭逻辑就会被调用。当前的实施和记录的 JEP 也将确保这也发生在
WM_QUERYENDSESSION
。在该 API 公开可用之前,情况将一直如此(至少是 JDK 21 的支持结束日期)。
使用此解决方案,您不必使用依赖于平台的库和
String
文字中指定的任何类名,只需使用 Signal
的名称,但据我所知,没有解决方法。 (您也可以以同样的方式添加对 TERM
的支持。)