Understanding Java ShutdownHook: Usage, Implementation, and Internals
This article explains how to add and use Java's ShutdownHook, details its internal data structures and execution order, describes system‑level and application‑level hooks, outlines the trigger points such as Runtime.exit and signal handling, and provides code examples for implementing graceful shutdowns.
Java provides a mechanism called ShutdownHook that allows developers to execute custom code when the JVM is shutting down.
Typical usage involves adding a hook at program start:
Runtime.getRuntime().addShutdownHook(new Thread(){
@Override
public void run() {
System.out.println("I'm shutdown hook...");
}
});ShutdownHooks are used for cleanup tasks, graceful release of resources, and smooth service shutdowns. Many frameworks such as Spring and Dubbo register their own hooks to destroy beans or stop services.
Internal data structures and execution order
When a hook is added, ApplicationShutdownHooks.add(hook) stores the thread in a static IdentityHashMap<Thread, Thread> called hooks . System‑level hooks are kept in a fixed‑size array (max 10) and are executed synchronously in the order they were registered.
Application‑level hooks are stored in the same map but are started as separate threads; they run asynchronously after the system hooks, and the JVM waits for all of them to finish before exiting.
private static void runHooks() {
for (int i = 0; i < MAX_SYSTEM_HOOKS; i++) {
try {
Runnable hook;
synchronized (lock) {
currentRunningHook = i;
hook = hooks[i];
}
if (hook != null) hook.run();
} catch (Throwable t) {
// handle errors
}
}
}The JVM triggers shutdown through two main entry points: Shutdown.exit (called by Runtime.exit or signal handlers) and Shutdown.shutdown (invoked by the JVM when the last non‑daemon thread finishes).
Signal handling
Custom signal handlers can be registered to intercept signals such as HUP, INT, TERM, etc. After handling, the handler should call System.exit to allow the shutdown hooks to run; otherwise the process may hang.
public class SignalHandlerTest implements SignalHandler {
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override public void run() {
System.out.println("I'm shutdown hook ");
}
});
SignalHandler sh = new SignalHandlerTest();
Signal.handle(new Signal("HUP"), sh);
// other signals...
while (true) {
System.out.println("main running");
Thread.sleep(2000L);
}
}
@Override public void handle(Signal signal) {
System.out.println("receive signal " + signal.getName());
System.exit(0);
}
}Key conclusions:
ShutdownHooks cover most termination scenarios except a forced kill ( kill -9 ), which cannot be intercepted.
System‑level hooks execute synchronously; application‑level hooks run asynchronously after them.
When implementing signal handling, remember to exit the JVM explicitly to let hooks run.
Full-Stack Internet Architecture
Introducing full-stack Internet architecture technologies centered on Java
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.