Reputation: 189
In my Java console application I catch a Ctrl+C key press and add a thread performing graceful shutdown using Runtime.getRuntime().addShutdownHook()
In this thread I process all oustanding work in some internal queues and exit my application gracefully which is normally what I want.
However, sometimes the application can have internal queues that take a while to proces (several minutes), if so I would like an option to press Ctrl+C a second time to forcibly exit the application.
I have seen other applications working this way but I cannot find myself how to catch the second Ctrl+C in Java?
Upvotes: 4
Views: 2077
Reputation: 7319
Use Signal.handle on SIGINT and in the handler, restore the original default SIG_DFL handler. So if it is hit a second time, it will terminate the program using the SIG_DFL handler (supplied by the OS).
private void registerSigIntHandler() {
Signal.handle(new Signal("INT"), new SignalHandler() {
public void handle(Signal sig) {
log.info("SIGINT received");
Signal.handle(new Signal("INT"), SignalHandler.SIG_DFL);
shutdown();
SignalHandler.SIG_DFL.handle(new Signal("INT"));
}
});
}
This also calls the SIG_DFL handler to terminate the process once your shutdown
method completes.
https://stackoverflow.com/a/71028985/854342
Upvotes: 0
Reputation: 6618
Warning, this is not what you should do. The usual reasons for avoiding the sun package apply. Think thrice before actually using this in real code. At minimum the access to the signal handling should be done with reflection and fall back to registering the usual shutdown hook when it fails. I left that out for brevity.
So, all hope abandon, ye who enter here:
import java.util.concurrent.atomic.AtomicBoolean;
import sun.misc.Signal;
import sun.misc.SignalHandler;
public class Sigint {
private static void prepareShutdownHandling() {
// This would be the normal shutdown hook
final Thread shutdown = new Thread() {
@Override
public void run() {
// Simulate slow shutdown
for (int i = 0; i < 10; i++) {
System.out.println("Normal shutdown running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Normal shutdown finished");
System.exit(0);
}
};
Signal.handle(new Signal("INT"), new SignalHandler() {
private AtomicBoolean inShutdown = new AtomicBoolean();
public void handle(Signal sig) {
if (inShutdown.compareAndSet(false, true)) {
// Normal shutdown
shutdown.start();
} else {
System.err.println("Emergency shutdown");
System.exit(1);
}
}
});
}
public static void main(String args[]) {
prepareShutdownHandling();
while (true) {
System.out.println("Main program running");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
Upvotes: 2