Catching Ctrl+C in Java
Asked Answered
B

3

105

Is it possible to catch the Ctrl+C signal in a java command-line application? I'd like to clean up some resources before terminating the program.

Bandur answered 23/10, 2009 at 7:49 Comment(1)
Related: Capture SIGINT in JavaLudendorff
C
104

You can attach a shutdown hook to the VM which gets run whenever the VM shuts down:

The Java virtual machine shuts down in response to two kinds of events:

  • The program exits normally, when the last non-daemon thread exits or when the exit (equivalently, System.exit) method is invoked, or

  • The virtual machine is terminated in response to a user interrupt, such as typing Ctrl+C, or a system-wide event, such as user logoff or system shutdown.

The thread you pass as shutdown hook has to follow several rules, though, so read the linked documentation carefully to avoid any problems. This includes ensuring thread-safety, quick termination of the thread, etc.

Also, as commenter Jesper points out, shutdown hooks are guaranteed to run on normal shutdown of the VM but if the VM process is terminated forcibly they don't. This can happen if native code screws up or if you forcibly kill the process (kill -9, taskkill /f).

But in those scenarios all bets are off anyway, so I wouldn't waste too much thought on it.

Conscionable answered 23/10, 2009 at 7:52 Comment(7)
Beware that shutdown hooks are not guaranteed to run under all circumstances; there might be situations where they are not run, so don't make the correct functioning of your program dependent on what you do in a shutdown hook.Drumstick
They are not run, when the process is terminated forcefully (TerminateProcess() or SIGKILL) but that's outside normal operation and since Ctrl+C is already covered by the shutdown hook, it's safe to use it. You can't do much if the OS actually terminates your process anyway.Conscionable
If I execute kill (sending a TERM signal), will this be caught in the shutdown hook? (Note that it's not the same as kill -9 which I understand from the above that it will not get caught in the hook.)Fleabite
Try it out. From what I understand, that's a soft »kill« where the program has still a chance to react properly. So it should work.Conscionable
kill -HUP is the "softest" kill from Unix, and should run the shutdown hook. Not sure about the default kill.Pentha
Default kill causes the shutdown hook to run on my machine (Redhat 7.3). Kill -9 does not.Mg
Shutdown hooks are not guaranteed to run in any particular order, so if your shutdown hook relies on other shutdown hooks not being run yet (or vice versa), you can run into problems.Felice
W
50

Just for quick console testing purposes...

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();
            }
        }
    });
Williamson answered 4/10, 2015 at 13:37 Comment(1)
With a lambda: Runtime.getRuntime().addShutdownHook(new Thread(() -> {/*code*/}));Ludendorff
F
15

The top answer suggests using a shutdown hook. Shutdown hooks are far more trouble than they are worth. They run in an indeterminate order, and libraries you depend upon may add their own shutdown hooks, which may mean that something your own shutdown hook depends upon may be de-initialized before your shutdown hook runs. Save yourself the headache, and use a signal handler:

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

Signal is currently sun.misc.Signal, which means it will be deprecated -- but what it's being replaced with is currently named jdk.internal.misc.Signal, so until the Java team figure out how to publicly expose signal handlers in a non-internal way, beware that this call may go away. For now though (as of JDK 11), sun.misc.Signal still exists.

Felice answered 22/11, 2020 at 12:48 Comment(4)
This generates an 'Access Restriction' for me: Access restriction: The type 'Signal' is not API (restriction on required library 'C:\Program Files\Java\jre1.8.0_221\lib\rt.jar')Chariot
@paul-carew Wow, they have already started locking down the API. Good to know, thanks for pointing that out. Although wait, this is for JDK 1.8.x? I would only expect this sort of warning on JDK 15 or later.Felice
@PaulCarew: they shouldn't lock down portions of their woefully lacuneous API without providing a better and officially supported way of doing things (and not jdk.internal.*) ...Bistoury
@Bistoury +1 for the API point, and I would give an additional +1 if I could, for the use of the word "lacuneous" :-)Felice

© 2022 - 2024 — McMap. All rights reserved.