I have a rather complicated shutdown in Java - there's a lot of clean up work to do. In particular I'm trying to figure out how to error handle from a shutdown hook thread. My code includes this currently:
try {
return shutdownPromise = doShutdown();
}
catch (Throwable exc) {
logger.error("An exception was thrown while shutting down the application.", exc);
System.exit(1);
return null;
}
When I originally wrote this I essentially thought, an error in shutdown should just go straight to exit
. But exit
is not so low level; it calls the shutdown hooks.
So I thought -
Firstly, the easy answer: your process deadlocks.
System.exit winds up calling Shutdown.exit
, which ends with this code block:
synchronized (Shutdown.class) {
/* Synchronize on the class object, causing any other thread
* that attempts to initiate shutdown to stall indefinitely
*/
sequence();
halt(status);
}
The comment is completely accurate. But to understand this we need to see exactly what the the shutdown hook does.
Shutdown hooks are added via ApplicationShutdownHooks.add
, as explained in this answer here. Note that the sequence
method above eventually winds up on this line of code in Shutdown.runHooks
:
if (hook != null) hook.run();
Firstly, note these hooks are not your application shutdown hooks. They are system shutdown hooks, which are different, and one of them is responsible for ensuring your application shutdown hooks run. Notice that is run, not start. In other words, it blocks. One of these shutdown hooks will be a system hook that concurrently starts all the application shutdown hooks (you can trace this code for yourself or in linked answer), then blocks until they all complete using a Thread.join
call. One of these will be your application shutdown hook - which, if it calls System.exit
, will be waiting to get the lock on Shutdown.class
forever.
Next, the dumb answer: call Runtime.getRuntime().halt()
instead. I say "the dumb answer" because this is probably the slightly lower level thing you were looking to do instead of exit. If System.exit
represents a clean shutdown that failed, then halt
is a hard shutdown that will always succeed immediately.
Next, the smarter answer: probably nothing. Just let your shutdown hook finish, for the following reasons. Your shutdown hook does not own the shutdown - in particular, there may be other shutdown hooks that need to do their work. Conversely, I suspect one of the responsibilities of this hook is to force a hard shutdown eventually. I would recommend creating that as a delayed task right away then letter this hook complete normally.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With