如何正常closures由于closures执行命令行而终止​​的Java应用程序?

关于正常closuresJava命令行程序的最佳途径有一个回答的问题。 当一个程序被Ctrl + C终止的时候,一个closures钩子完成了这个工作。

我的问题是,如果命令行本身在Java程序执行过程中被closures,该如何正常退出? 我用shutdown hook进行了testing,但在这种情况下不起作用。 在这种情况下,我找不到虚拟机会发生什么情况。 这个进程及其所有线程立即死亡? closures命令行产生什么样的信号?

那么,这个问题怎么解决呢?

编辑:问题涉及Windows环境。

从逻辑上讲,应该提高SIGHUP(终端挂断)。

其实,我只是用一个简单的shell脚本来检查我的猜测。 是的,当用户关闭一个终端仿真程序,在该终端仿真程序中,应用程序已经启动(并且从中未被分离),那么应用程序会收到SIGHUP。 所以建立一个SIGHUP处理程序并作出相应的反应。 通常的行为是终止一个应用程序,但你的意图可能是不同的。

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

对于Windows来说,看看Catch Windows终端关闭正在运行的进程

编辑Windows环境:

我在Windows环境上没有太多的经验,但是如果你希望你的应用程序能够继续运行的话,它通常被部署为Windows服务(它类似于Linux上的守护进程)。 你通常会通过一个列出所有服务的实用程序(我想你可以通过控制面板 – >管理工具 – >服务来启动/停止/重新启动服务),我猜想通过这个工具发出一个“停止”如果你通过任务管理器终止服务,那么它将不会是一个正常的关闭。


这是基于Linux还是基于Windows的环境? 在Linux中,如果您在后台运行程序(并使用'exit'命令退出shell),它将继续运行。 您可以通过在最后添加一个&来将您的应用程序置于后台。 另外,很多应用程序/服务在后台运行。 如果使用startup.sh命令执行Tomcat启动脚本,即使退出启动的终端,也将继续在后台运行。 在窗户上,这个概念应该是相似的。

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

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

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

即使程序正常结束,关闭挂钩仍在调用中。 在这种情况下,使用removeShutdownHook (仍然是Runtime方法)退出之前删除注册的钩子是更清洁的。

编辑:

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

  • PostQuitMessage函数在进程事件循环中发送一个WM_QUIT消息 – 通常进程应该退出,但是可以进行清理(Unix SIG_TERM等价)
  • TerminateProcess立即停止进程及其所有线程(Unix SIG_KILL的等价性)

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