17

cmd.exe在 Windows 中运行我的 Java 应用程序。如果我通过按 Ctrl-C 强制停止该过程,并且当时的代码正在块中运行,那么tryfinally块是否仍会执行?

在我的测试中,似乎是的,它被执行了。

4

5 回答 5

18

确保运行某些代码以响应操作系统信号(这是 Ctrl-C 所做的,它发送 SIGINT)的正确方法是注册“shutdownHook”。这是一个关于处理它的StackOverflow 问题,这是一篇关于 JVM 信号处理的详细信息,比您可能想知道的要多得多。

于 2011-02-06T05:25:14.097 回答
12

虽然您的 finally 代码可能已经在您的 Windows 机器上执行(我无法用 Linux 重现它),但根据finally 上的文档

注意:如果在执行 try 或 catch 代码时 JVM 退出,则 finally 块可能不会执行。同样,如果执行 try 或 catch 代码的线程被中断或杀死,即使应用程序作为一个整体继续运行,finally 块也可能不会执行。

所以我不会使用 finally 块来确保一段代码执行,即使用户试图过早退出。如果你需要,你可以像Adrian Petrescu提到的那样使用Shutdown Hooks

于 2011-02-06T05:29:28.127 回答
3

在我在 Windows 7、Sun Java 1.6 上的测试中,如果我在这个 try 块期间按下 Ctrl-C,finally 块不会执行。

public static void main(String[] args) {
    try {
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }
    finally {
        System.out.println("finally");
    }
}
于 2011-02-06T05:32:01.073 回答
0

根据操作系统的实现,通常sigkills意味着立即停止应用程序。在这种情况下,不希望依赖 finally 块来执行;在某些情况下可能会,但通常会/不应该。该java.lang.Runtime文档进一步支持这一点:

In rare circumstances the virtual machine may abort, that is, stop running without shutting down cleanly. This occurs when the virtual machine is terminated externally, for example with the SIGKILL signal on Unix or the TerminateProcess call on Microsoft Windows. The virtual machine may also abort if a native method goes awry by, for example, corrupting internal data structures or attempting to access nonexistent memory. If the virtual machine aborts then no guarantee can be made about whether or not any shutdown hooks will be run.

于 2017-12-21T16:31:19.797 回答
0

不,当我 Ctrl-C(在 Linux 中)时,finally 块没有为我运行。

我建议将您的最终逻辑移至“关闭”方法。然后从 finally 块以及 Ctrl-C 处理程序调用它。像这样:

private void registerSigIntHandler() {
    final SignalHandler defaultSigIntHandler = Signal.handle(new Signal("INT"), SignalHandler.SIG_DFL);

    Signal.handle(new Signal("INT"), new SignalHandler() {
        public void handle(Signal signal) {
            log.info("SIGINT received");
            Signal.handle(new Signal("INT"), SignalHandler.SIG_DFL);
            shutdown();
            defaultSigIntHandler.handle(signal);        }
    });
}

这样做的好处是关闭完成后,SIG_DFL 处理程序将执行,通过默认的 OS SIGINT 处理程序终止程序。这会终止主线程和整个进程。否则,如果你不使用 SIG_DFL,你必须以某种方式通知主线程退出。我的主线程不侦听/轮询关闭信号/消息。这是一项长期运行的数据迁移工作。我想关闭某些东西但终止主线程和子线程。

此外,如果关闭挂起(希望不会发生),第二个 ctrl-c 将通过 SIG_DFL 处理程序终止程序。

在关机时,我还设置了一个 AtomicBoolean 以确保关机只运行一次。

boolean isShuttingDown = this.isShuttingDown.getAndSet(true);
if (isShuttingDown) {
    return;
}

我也尝试过addShutdownHook(的替代方法Signal.handle),但遇到了麻烦,因为它没有完全运行我的关机程序。我正在发送消息并加入子线程。

注意:不要调用SignalHandler.SIG_DFL.handle(new Signal("INT"));。它每次都给我 SIGSEGV (确实退出程序)。-如何触发默认信号处理行为?

于 2022-02-08T05:28:54.457 回答