Adding Shutdown Hooks for JVM Applications

1. Overview

It’s typically easy to start-up a service. However, sometimes we need to have a plan for gracefully shutting one down.

In this tutorial, we’re going to take a look at different ways a JVM application can terminate. Then, we’ll use Java APIs to manage JVM shutdown hooks. Please refer to this article to learn more about shutting down the JVM in Java applications.

2. JVM Shutdown

The JVM can be shut down in two different ways:

  1. A controlled process
  2. An abrupt manner

A controlled process shuts down the JVM when either:

  • The last non-daemon thread terminates. For example, when the main thread exits, the JVM starts its shutdown process
  • Sending an interrupt signal from the OS. For instance, by pressing Ctrl + C or logging off the OS
  • Calling System.exit() from Java code

While we all strive for graceful shutdowns, sometimes the JVM may shut down in an abrupt and unexpected manner. The JVM shuts down abruptly when:

  • Sending a kill signal from the OS. For example, by issuing a kill -9 <jvm_pid>
  • Calling Runtime.getRuntime().halt() from Java code
  • The host OS dies unexpectedly, for example, in a power failure or OS panic

3. Shutdown Hooks

The JVM allows registering functions to run before it completes its shutdown. These functions are usually a good place for releasing resources or other similar house-keeping tasks. In JVM terminology, these functions are called shutdown hooks.

Shutdown hooks are basically initialized but unstarted threads. When the JVM begins its shutdown process, it will start all registered hooks in an unspecified order. After running all hooks, the JVM will halt.

3.1. Adding Hooks

In order to add a shutdown hook, we can use the Runtime.getRuntime().addShutdownHook() method:

Thread printingHook = new Thread(() -> System.out.println("In the middle of a shutdown"));
Runtime.getRuntime().addShutdownHook(printingHook);

Here we simply print something to the standard output before JVM shuts down itself. If we shut down the JVM like following:

> System.exit(129);
In the middle of a shutdown

Then we’ll see that the hook actually prints the message to standard output.

The JVM is responsible for starting hook threads. Therefore, if the given hook has been already started, Java will throw an exception:

Thread longRunningHook = new Thread(() -> {
    try {
        Thread.sleep(300);
    } catch (InterruptedException ignored) {}
});
longRunningHook.start();

assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(longRunningHook))
  .isInstanceOf(IllegalArgumentException.class)
  .hasMessage("Hook already running");

Obviously, we also can’t register a hook multiple times:

Thread unfortunateHook = new Thread(() -> {});
Runtime.getRuntime().addShutdownHook(unfortunateHook);

assertThatThrownBy(() -> Runtime.getRuntime().addShutdownHook(unfortunateHook))
  .isInstanceOf(IllegalArgumentException.class)
  .hasMessage("Hook previously registered");

3.2. Removing Hooks

Java provides a twin remove method to remove a particular shutdown hook after registering it:

Thread willNotRun = new Thread(() -> System.out.println("Won't run!"));
Runtime.getRuntime().addShutdownHook(willNotRun);

assertThat(Runtime.getRuntime().removeShutdownHook(willNotRun)).isTrue();

The removeShutdownHook() method returns true when the shutdown hook is successfully removed.

3.3. Caveats

The JVM runs shutdown hooks only in case of normal terminations. So, when an external force kills the JVM process abruptly, the JVM won’t get a chance to execute shutdown hooks. Additionally, halting the JVM from Java code will also have the same effect:

Thread haltedHook = new Thread(() -> System.out.println("Halted abruptly"));
Runtime.getRuntime().addShutdownHook(haltedHook);
        
Runtime.getRuntime().halt(129);

The halt method forcibly terminates the currently running JVM. Therefore, registered shutdown hooks won’t get a chance to execute.

4. Conclusion

In this tutorial, we looked at different ways a JVM application can possibly terminate. Then, we used a few runtime APIs to register and de-register shutdown hooks.

As usual, the sample code is available over on GitHub.

Related posts:

Java Program to Implement the linear congruential generator for Pseudo Random Number Generation
Introduction to Spliterator in Java
Abstract class và Interface trong Java
Các nguyên lý thiết kế hướng đối tượng – SOLID
Shuffling Collections In Java
Convert char to String in Java
Java Program to Create a Minimal Set of All Edges Whose Addition will Convert it to a Strongly Conne...
Java Program to Implement LinkedBlockingQueue API
So sánh HashMap và HashSet trong Java
Getting the Size of an Iterable in Java
Using a List of Values in a JdbcTemplate IN Clause
Java Program to Find the Longest Subsequence Common to All Sequences in a Set of Sequences
Java Program to Implement Self organizing List
Show Hibernate/JPA SQL Statements from Spring Boot
Spring @Primary Annotation
Java Program to Perform Partial Key Search in a K-D Tree
Java Program to Find the Longest Path in a DAG
Spring Security 5 – OAuth2 Login
Java – InputStream to Reader
Most commonly used String methods in Java
Java Program to Check if a Point d lies Inside or Outside a Circle Defined by Points a, b, c in a Pl...
New Features in Java 14
Java Program to Implement DelayQueue API
Java Program to Generate a Sequence of N Characters for a Given Specific Case
Marker Interface trong Java
Java Program to Implement wheel Sieve to Generate Prime Numbers Between Given Range
How to Define a Spring Boot Filter?
Adding a Newline Character to a String in Java
How to Get a Name of a Method Being Executed?
Spring Security and OpenID Connect
Converting Between an Array and a Set in Java
Java Program to Generate All Possible Combinations Out of a, b, c, d, e