开发者

If I type Ctrl-C on the command line, will the finally block in Java still execute?

I'm running my Java application in cmd.exe in Windows. If I stop the process forcefully by pressing Ctrl-C, and the code at that moment was running in 开发者_StackOverflow社区the try block, will the finally block still be executed?

In my tests it seems that, yes, it is executed.


The correct way to ensure that some code is run in response to an operating system signal (which is what Ctrl-C does, it sends a SIGINT) is to register a "shutdownHook". Here's a StackOverflow question about handling it, and here's an article with way more detail about the JVM's signal handling than you probably will ever want to know.


While your finally code may have executed on your Windows machine (I couldn't reproduce it with Linux), according to this documentation on finally:

Note: If the JVM exits while the try or catch code is being executed, then the finally block may not execute. Likewise, if the thread executing the try or catch code is interrupted or killed, the finally block may not execute even though the application as a whole continues.

So I wouldn't use a finally block to make sure a piece of code executes, even if the user tries to prematurely exit. If you need that, you can use, like Adrian Petrescu mentioned, Shutdown Hooks


In my test on Windows 7, Sun Java 1.6, the finally block did not execute if I pressed Ctrl-C during this try block.

public static void main(String[] args) {
    try {
        for (int i = 0; i < 1000; i++) {
            System.out.println(i);
        }
    }
    finally {
        System.out.println("finally");
    }
}


Depending on OS implementations, generally sigkills are meant to stop applications immediately. In this situation it is not desirable to rely on finally block to execute; it may in some situations, but generally it would/should not. The java.lang.Runtime documentation further supports this:

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.


No, the finally block is not being run for me when I Ctrl-C (in Linux).

I recommend moving your finally logic to a method "shutdown". Then calling it from both the finally block as well as from a Ctrl-C handler. Like this:

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);        }
    });
}

The benefit of doing it this way is that after shutdown completes, the SIG_DFL handler executes, terminating the program via the default OS SIGINT handler. This terminates the main thread and the entire process. Otherwise, if you do not use SIG_DFL, you have to somehow signal the main thread to exit. My main thread does not listen/poll for shutdown signals/messages. It is a long-running data-migration job. I want to shut down certain things but terminate the main thread and subthreads.

Also if shutdown hangs (hopefully should not happen), a second ctrl-c will terminate the program via the SIG_DFL handler.

In shutdown, I also set an AtomicBoolean to ensure shutdown is only run once.

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

I also tried addShutdownHook (an alternative to Signal.handle) but ran into trouble with it not running my shutdown routine fully. I was messaging and joining with subthreads.

Note: Do not call SignalHandler.SIG_DFL.handle(new Signal("INT"));. It gives me SIGSEGV every time (which does exit the program). - How do I trigger the default signal handling behavior?

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜