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 Solve a Matching Problem for a Given Specific Case
Spring REST API with Protocol Buffers
Spring Cloud Series – The Gateway Pattern
Java Program to Implement the Alexander Bogomolny’s UnOrdered Permutation Algorithm for Elements Fro...
Java Program to Find kth Largest Element in a Sequence
Vấn đề Nhà sản xuất (Producer) – Người tiêu dùng (Consumer) và đồng bộ hóa các luồng trong Java
Java Program to Implement Unrolled Linked List
Properties with Spring and Spring Boot
A Guide to BitSet in Java
Java Program to Perform Naive String Matching
Spring – Injecting Collections
How to Round a Number to N Decimal Places in Java
Request a Delivery / Read Receipt in Javamail
Injecting Prototype Beans into a Singleton Instance in Spring
Jackson – Bidirectional Relationships
Java Program to Implement Singly Linked List
Immutable Objects in Java
Java Program to Implement Warshall Algorithm
Guide to Guava Table
Introduction to Spring Cloud CLI
Handling Errors in Spring WebFlux
Returning Image/Media Data with Spring MVC
Java Program to Convert a Decimal Number to Binary Number using Stacks
Java Program to Implement TreeSet API
Java Program to Perform String Matching Using String Library
Get the workstation name or IP
Spring Webflux and CORS
Lớp TreeMap trong Java
Jackson – Unmarshall to Collection/Array
Java Program to Implement Hash Tables with Quadratic Probing
Java Program to Implement Solovay Strassen Primality Test Algorithm
Java Program to Implement Tarjan Algorithm