90

是否可以在 java 命令行应用程序中捕获Ctrl+信号?C我想在终止程序之前清理一些资源。

4

3 回答 3

94

您可以将关闭挂钩附加到虚拟机,该挂钩会在虚拟机关闭时运行:

Java 虚拟机关闭以响应两种事件:

  • 程序正常退出,当最后一个非守护线程退出或调用 exit(等效于 System.exit)方法时,或

  • 虚拟机响应用户中断(例如键入Ctrl+ C)或系统范围的事件(例如用户注销或系统关闭)而终止。

但是,作为关闭挂钩传递的线程必须遵循几条规则,因此请仔细阅读链接文档以避免任何问题。这包括确保线程安全、线程的快速终止等。

此外,正如评论者 Jesper 指出的那样,关闭挂钩可以保证在 VM 正常关闭时运行,但如果 VM 进程被强制终止,它们不会。如果本机代码出错或您强行终止进程 ( kill -9, taskkill /f),就会发生这种情况。

但在这些情况下,无论如何,所有的赌注都没有了,所以我不会在这上面浪费太多的心思。

于 2009-10-23T07:52:57.587 回答
41

仅用于快速控制台测试目的...

Runtime.getRuntime().addShutdownHook(new Thread() {
        public void run() {
            try {
                Thread.sleep(200);
                System.out.println("Shutting down ...");
                //some cleaning up code...

            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
                e.printStackTrace();
            }
        }
    });
于 2015-10-04T13:37:38.187 回答
8

最佳答案建议使用关闭挂钩。关闭钩子带来的麻烦远多于其价值。它们以不确定的顺序运行,您所依赖的库可能会添加自己的关闭挂钩,这可能意味着您自己的关闭挂钩所依赖的某些东西可能会在您的关闭挂钩运行之前被取消初始化。省去自己的麻烦,并使用信号处理程序:

Signal.handle(new Signal("INT"),  // SIGINT
    signal -> System.out.println("Interrupted by Ctrl+C"));

Signalis current sun.misc.Signal,这意味着它将被弃用——但它被替换的内容是 current named jdk.internal.misc.Signal,所以在 Java 团队弄清楚如何以非内部方式公开信号处理程序之前,请注意这个调用可能会消失。不过现在(从 JDK 11 开始)sun.misc.Signal仍然存在。

于 2020-11-22T12:48:54.503 回答