如何正常关闭因关闭执行命令行而终止​​的Java应用程序?

时间:2014-11-27 07:49:56

标签: java windows command-line exit

Best Way to Gracefully Shutdown a Java Command Line Program上有一个已回答的问题。当程序被Ctrl + C终止时,关闭钩子可以完成这项工作。

我的问题是如果在执行Java程序期间命令行本身被关闭,如何优雅地退出?我用关机钩测试但在这种情况下它没有工作。我不知道在这种情况下虚拟机会发生什么。该过程及其所有线程是否立即被杀死? 关闭命令行产生什么样的信号?

那么,这个特殊问题怎么解决?

编辑:问题与Windows环境有关。

3 个答案:

答案 0 :(得分:2)

逻辑上,应该引发SIGHUP(终端挂断)。

实际上,我刚用一个简单的shell脚本检查了我的猜测。是的,当用户关闭启动了应用程序(并且未从中分离)的终端仿真器时,应用程序将收到SIGHUP。所以设置一个SIGHUP处理程序并做出相应的反应。通常的行为是终止应用程序,但您的意图可能不同。

此外,如果您的Java应用程序执行任何STDIN / STDOUT操作,它应该在收到HUP时关闭或至少重新配置,因为尝试从非现有终端读/写将导致SIGPIPE和/或程序块

对于Windows,请查看Catch Windows terminal closing on running process

答案 1 :(得分:0)

编辑Windows环境:

我对Windows环境没有太多经验,但如果您希望应用程序继续运行,它通常部署为Windows服务(它类似于Linux上的守护程序)。您通常会通过列出所有服务的实用程序启动/停止/重新启动服务(我认为您通过控制面板访问它 - >管理工具 - >服务。我猜想通过此工具发出“停止”会发出信号如果你通过任务管理器终止服务,那么它就不会正常关闭。


这是基于Linux还是基于Windows的环境?在Linux中,如果你在后台运行程序(并使用'exit'命令退出shell),它将继续运行。您可以通过添加&和/或在末尾。此外,许多应用程序/服务在后台运行。如果使用startup.sh命令执行Tomcat启动脚本,即使退出启动它的终端,它也会在后台继续运行。在Windows上,概念也应该类似。

在关闭应用程序方面,您在Linux系统上使用kill命令。进程上的kill命令向其发送SIGTERM信号。应用程序可以实现代码来拦截SIGTERM并在检测到SIGTERM时正常关闭。如果应用程序没有正常处理SIGTERM,那么它将不响应SIGTERM / kill。在这种情况下,你需要明确地给它一个SIGKILL(kill -9)来强行杀死它。在这种情况下,无法正常关机。

答案 2 :(得分:0)

在Java中,有一种特殊的Runtime方法:addShutdownHook

这允许您初始化JVM在停止之前尝试运行的线程。即使在关闭父窗口的Ctrl-C的情况下,也要 放置要执行的清理。从javadoc解压缩:关闭钩子只是一个初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩,并让它们同时运行。当所有挂钩都完成后,如果启用了finalization-on-exit,它将运行所有未读取的终结器。最后,虚拟机将停止。

即使程序正常结束,也会调用shutdown hook。在这种情况下,在退出removeShutdownHook之前删除已注册的钩子更为清晰(仍然是来自Runtime的方法)

编辑:

在Windows环境中,没有真正的信号,但在系统关闭时会有特殊的回调。 AFAIK,系统挂钩在这种情况下被正确调用,但我承认我从未真正测试过。在Windows中,可以要求进程以两种方式终止:

  • PostQuitMessage函数在进程事件循环中发布WM_QUIT消息 - 通常进程应该退出,但它可以进行清理(等同于Unix SIG_TERM)
  • TerminateProcess立即停止进程及其所有线程(等同于Unix SIG_KILL)

控制台进程可以使用可以拦截Ctrl-C,Ctrl-Break或Ctrl-Close事件的ConsoleControlHandler。前两个是通过键盘生成的,最后一个是在用户关闭控制台时生成的。但通常情况下,Oracle JVM在获取与SIGTERM相同的Ctrl-Close事件时应使用系统钩子机制。