优雅关闭 Java 命令行程序的最佳方法

Posted

技术标签:

【中文标题】优雅关闭 Java 命令行程序的最佳方法【英文标题】:Best Way to Gracefully Shutdown a Java Command Line Program 【发布时间】:2010-11-04 22:45:12 【问题描述】:

我对优雅地关闭 Java 命令行程序的不同方法感兴趣。发送终止信号不是一种选择。

我能想到几种不同的方法。

    打开一个端口并等待连接。制作完成后,优雅地关闭。 观察要创建的文件,然后关闭。 从终端读取一些输入,例如“执行关机”。

第三个并不理想,因为经常有节目输出被泵送到屏幕上。第一个需要太多努力(我很懒)。大多数程序员是否使用第二种选择?如果没有,还有什么可能/优雅/简单?

【问题讨论】:

你的意思是让一个进程杀死你的java命令行程序? 为什么不能发送终止信号?正如下面的答案中提到的,您可以使用关闭挂钩优雅地捕获和处理终止信号。 【参考方案1】:

你可以试试这样的:

Runtime.getRuntime().addShutdownHook(new Thread() 
    public void run()  /*
       my shutdown code here
    */ 
 );

编辑:

关闭钩子不会执行应用程序的关闭。相反,它为开发人员提供了一种在关机时执行他/她希望进行的任何清理的方法。

来自Runtime 的 JavaDoc(如果您打算使用此方法,请阅读):

关闭挂钩只是一个已初始化但未启动的线程。当虚拟机开始其关闭序列时,它将以某种未指定的顺序启动所有已注册的关闭挂钩并让它们同时运行。当所有钩子都完成后,如果 finalization-on-exit 已启用,它将运行所有未调用的终结器。最后,虚拟机将停止。 ...

【讨论】:

如何关闭他的程序? run方法不应该有@Override注解吗? 当我通过单击“x”按钮 (Windows) 关闭命令提示符时,这会起作用吗? 不知道为什么这个答案的支持率最高 - 它完全不相关(执行关闭,这是 OP 要求的)【参考方案2】:

您可以尝试使用满足您要求的Runtime.getRuntime().addShutdownHook()。通过这种方式,您可以注册一个钩子来进行清理,以便执行正常关闭。

编辑

http://java.sun.com/j2se/1.4.2/docs/api/java/lang/Runtime.html#addShutdownHook(java.lang.Thread) 公共无效 addShutdownHook(线程挂钩) 注册一个新的虚拟机关闭挂钩。 Java 虚拟机关闭以响应两种事件:

程序正常退出,当最后一个非守护线程退出或调用 exit(等效于 System.exit)方法时,或 虚拟机响应用户中断(例如键入 ^C)或系统范围的事件(例如用户注销或系统关闭)而终止。

【讨论】:

但是 mike,这是优雅降级的方式,如果按下 ctrl+c,任何 cmd 程序都会以终止信号终止。 您提到的其他选项都不会,因此 ctrl+c 上的行为可能与决定其中一种方法无关。 javadoc 明确表示它是在 ctrl-c 上调用的 我刚刚测试并在 ctrl-c 上调用了关闭挂钩(至少在运行 java 1.5.0_16 的 Mac OS X 10.5 上) 当心 -Xrs java 命令行选项:它掩盖了 SIGINT、SIGTERM、SIGHUP 和 SIGQUIT。【参考方案3】:

第二个选项 - 检查文件 - 优于第一个 - 侦听端口 - 的好处是您有一定的安全性。

您可以对创建文件的目录设置权限,以便只有适当的用户才能关闭程序。如果你监听一个端口,任何用户都可以连接到它。

【讨论】:

您可以根据客户端 IP 地址限制来电。例如,只允许来自本地主机的连接。只有当它是正确的 IP 地址时才退出,否则关闭连接并继续侦听新的。 @kd304 - 限制 IP 地址仍然允许本地系统上的任何用户关闭进程。通过在目录上设置权限,您只能允许特定用户控制进程。【参考方案4】:

如果你想使用socket版本,实现起来非常简单。代码如下:

ServerSocket server = new ServerSocket(8080);
System.out.println("Socket listening!");
server.accept();
System.out.println("Connection received!");

您可以轻松地将此代码嵌入到您的程序启动的单独线程中,然后让它修改全局状态以启动关闭。

【讨论】:

【参考方案5】:

前两个选项很容易实现。你也可以使用一些 JMX 的东西(我对此不太了解)。 Tomcat 使用第一种方法,我在我的两个项目中应用了 1 和 2。

【讨论】:

【参考方案6】:

考虑拥有一个 JMX 组件。然后,您可以在本地或通过网络连接 JConsole,并与您的组件进行通信。然后组件就可以正常关闭程序了。

对于 Java 6 u 10 或更高版本,您可以对 JVisualVM 执行相同操作。

【讨论】:

【参考方案7】:

我建议使用关闭挂钩。它将允许您使用标准操作系统工具来控制您的程序。它也不需要对外部资源(磁盘、端口等)的任何额外访问。

【讨论】:

执行关闭,这是 OP 要求的

以上是关于优雅关闭 Java 命令行程序的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

解析命令行参数的最佳方法是啥? [关闭]

在 C++ 中解析命令行参数? [关闭]

在 C++ 中解析命令行参数? [关闭]

关闭 Windows 控制台时如何优雅地关闭 Java 应用程序?

在 C# 中处理命令行选项的最佳方法 [重复]

是否有有助于构建命令行应用程序的良好 Java 库? [关闭]