library
advancedShutdown Hooks & Graceful Termination
Register cleanup logic for JVM shutdown and design applications for graceful termination.
A shutdown hook is a thread the JVM runs on its way out.
Shutdown hook = a 'close out' procedure at a store. When the 'closing time' signal comes (shutdown), the staff (hooks) rush to finish tasks: close the register (flush buffers), lock the doors (close connections), turn off lights (release resources).
Key Concepts
1
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("shutting down");
pool.shutdown();
dataSource.close();
}));2
When they run.
System.exit(n)
SIGTERM the normal docker stop, kubectl delete, Ctrl+C
the last non-daemon thread finishes3
When they do not.
SIGKILL (kill -9) nothing runs
a JVM crash
Runtime.halt() deliberately skips them4
So a hook is a best effort. Anything that must survive a hard kill needs to be durable before the kill, not
cleaned up after.
5
All hooks start at once, in no defined order, and the JVM waits for all of them. So one hook that blocks
forever hangs the shutdown — which is why the orchestrator eventually sends SIGKILL.
6
Graceful shutdown is more than a hook. The pattern is: stop accepting work, finish what is in flight,
then exit.
7
private volatile boolean running = true;8
void loop() {
while (running) { handle(queue.take()); }
}9
// in the hook
running = false;
pool.shutdown(); // no new tasks
if (!pool.awaitTermination(30, SECONDS))
pool.shutdownNow(); // then interrupt10
volatile on the flag is required. Without it the loop thread may never see the change, because the JVM
is free to keep it in a register.
volatile
11
shutdown versus shutdownNow.
shutdown() refuse new tasks, let running ones finish
shutdownNow() also interrupt the running ones, return the queuedshutdownshutdownNow
12
Call shutdown, wait, then shutdownNow as a fallback. Calling shutdownNow first discards queued work.
shutdownshutdownNow
13
Daemon threads get no hook of their own. When the last non-daemon thread ends, daemon threads are killed
where they stand, mid-write if that is where they are. Use setDaemon(true) for background work that must
never block exit, and not for anything holding state.
setDaemon(true)
14
Spring Boot does this already — the context closes, @PreDestroy runs, and the web server drains. A
standalone application writes the hook itself.
@PreDestroy
15
What the interviewer is probing.1. "When does a shutdown hook not run?" Probing: the limits. Stalls: "It always runs."
Moves up: not on SIGKILL, a JVM crash, or Runtime.halt — so anything that must survive has to be
durable before the kill.
16
2. "What order do hooks run in?" Probing: a wrong assumption people build on. Stalls:
"Registration order." Moves up: all start concurrently in no defined order, and the JVM waits for
all of them, so one that blocks hangs shutdown.
17
3. "Why must the running flag be volatile?" Probing: visibility. Stalls: "It is just a
boolean." Moves up: without it the loop thread may never see the change, because the JVM can keep
the value in a register.
18
4. "shutdown or shutdownNow?" Probing: the ordering that avoids losing work. Stalls:
"shutdownNow, it is faster." Moves up: shutdown, then awaitTermination, then shutdownNow as a
fallback — calling shutdownNow first discards everything queued.