How to Safely Use Java Shutdown Hooks to Clean Up Resources on JVM Exit
This article explains the purpose and inner workings of Java's Runtime.addShutdownHook, walks through the Runtime and ApplicationShutdownHooks source code, demonstrates practical usage with examples, discusses common scenarios, potential risks, and best‑practice solutions for reliable resource cleanup during JVM shutdown.
1. Question
How can we perform actions such as closing remote connections when the JVM exits?
2. Introduction to ShutdownHook
Java provides the method Runtime.getRuntime().addShutdownHook to register a shutdown hook. A shutdown hook is essentially a thread that the JVM starts during its shutdown sequence.
1. Runtime Class
Inspecting the source of Runtime reveals the addShutdownHook method.
1.1 Method Explanation
The JVM triggers registered shutdown hooks when it shuts down, either because the last non‑daemon thread exits, System.exit is called, or a user/system interrupt occurs.
Registers a new virtual‑machine shutdown hook
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 System.exit is invoked.
- The virtual machine is terminated in response to a user interrupt (e.g., ^C) or a system‑wide event such as user logoff or system shutdown.
A shutdown hook is simply an initialized but unstarted thread. When the virtual machine begins its shutdown sequence it will start all registered shutdown hooks in some unspecified order and let them run concurrently.
When all the hooks have finished it will then halt. Daemon threads continue to run during the shutdown sequence, as will non‑daemon threads if shutdown was initiated by invoking the exit method.1.2 Method Source Code
public void addShutdownHook(Thread hook) {
@SuppressWarnings("removal")
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new RuntimePermission("shutdownHooks"));
}
ApplicationShutdownHooks.add(hook);
}The method internally calls ApplicationShutdownHooks.add.
2. ApplicationShutdownHooks Class
2.1 Adding a Hook
private static IdentityHashMap<Thread, Thread> hooks;
static synchronized void add(Thread hook) {
if (hooks == null) throw new IllegalStateException("Shutdown in progress");
if (hook.isAlive()) throw new IllegalArgumentException("Hook already running");
if (hooks.containsKey(hook)) throw new IllegalArgumentException("Hook previously registered");
hooks.put(hook, hook);
}After adding a hook (a thread), the JVM will later execute it via runHooks.
2.2 Executing Hooks
static void runHooks() {
Collection<Thread> threads;
synchronized (ApplicationShutdownHooks.class) {
threads = hooks.keySet();
hooks = null;
}
for (Thread hook : threads) {
hook.start();
}
for (Thread hook : threads) {
while (true) {
try {
hook.join();
break;
} catch (InterruptedException ignored) {}
}
}
}During runHooks, all registered hook threads are started and the JVM waits for each to finish.
2.3 Execution Timing
The shutdown sequence follows this call chain:
System.exit → Runtime.exit → Shutdown → runHooks → ApplicationShutdownHooks.runHooks → start hook threads.
3. Example
Below is a simple program that registers a shutdown hook which prints a message when the JVM terminates.
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread() {
@Override
public void run() {
System.out.println("Waiting for me");
}
};
Runtime.getRuntime().addShutdownHook(thread);
System.out.println("Program ending");
}Output:
Program ending
Waiting for me4. Application Scenarios
Typical uses include closing connections, stopping threads, releasing resources, and recording execution state before the JVM shuts down.
5. Risks
5.1 Long‑Running Hooks
If a hook thread runs for a long time, the JVM will wait for it, delaying shutdown. For example, a hook that sleeps for several minutes will cause the shutdown command to block until it finishes.
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread() {
@Override
public void run() {
try {
Thread.sleep(1000 * 300);
} catch (InterruptedException e) { e.printStackTrace(); }
System.out.println(new Date() + " Waiting 5 minutes");
}
};
Runtime.getRuntime().addShutdownHook(thread);
System.out.println(new Date() + " Program closing");
}5.2 Cause
The JVM invokes ApplicationShutdownHooks.runHooks during exit, and each hook thread is joined via hook.join(), causing the main thread to wait.
5.3 Solutions
Control the execution logic and duration of hook code.
Use forced termination (e.g., kill -9) if necessary.
6. Extensions
Many frameworks leverage addShutdownHook for resource cleanup. For instance, Spring registers shutdown hooks, and the @PreDestroy annotation triggers cleanup before bean destruction.
7. Summary
1) This article introduced the purpose, implementation, and risks of Java shutdown hooks.
2) In practice you can register your own hooks to proactively release resources and reduce shutdown‑related risks.
3) Feel free to share feedback and discuss other Java topics.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JD Cloud Developers
JD Cloud Developers (Developer of JD Technology) is a JD Technology Group platform offering technical sharing and communication for AI, cloud computing, IoT and related developers. It publishes JD product technical information, industry content, and tech event news. Embrace technology and partner with developers to envision the future.
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.
