在Java中捕获Ctrl + C.

Pie*_*rre 73 java command-line control-c

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

Joe*_*oey 83

您可以将关闭挂钩附加到VM,该VM在VM关闭时运行:

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

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

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

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

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

但在这些情况下,所有赌注都是关闭的,所以我不会浪费太多的想法.

  • 当进程被强制终止(`TerminateProcess()`或`SIGKILL`)时,它们不会运行,但是这超出了正常操作的范围,并且由于Ctrl + C已被关闭钩子覆盖,因此可以安全地使用它。如果操作系统实际上终止了您的进程,您将无能为力。 (3认同)
  • 不保证关闭挂钩以任何特定顺序运行,因此如果您的关闭挂钩依赖于其他尚未运行的关闭挂钩(反之亦然),您可能会遇到问题。 (2认同)

bko*_*mac 25

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

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();
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

  • 使用 lambda:`Runtime.getRuntime().addShutdownHook(new Thread(() -> {/*code*/}));` (5认同)

Luk*_*son 15

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

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

Signal目前是sun.misc.Signal,这意味着它将被弃用 - 但它被替换的当前名称是jdk.internal.misc.Signal,因此在 Java 团队弄清楚如何以非内部方式公开公开信号处理程序之前,请注意此调用可能会消失。但目前(从 JDK 11 开始),sun.misc.Signal仍然存在。

  • @PaulCarew:他们不应该在不提供*更好的*和官方支持的做事方式(而不是 jdk.internal.*)的情况下锁定其严重缺陷的 API 的部分...... (5认同)