- JVM Shutdown Hook in Java
- Java
- Java
- Guide to JVM Shutdown
- 2. JVM Shutdown
- 2.1. Normal Shutdown by Thread Count
- 2.2. Normal Shutdown with System.exit
- 2.3. Normal Shutdown with CTRL-C
- 2.4. Abrupt Shutdown with System.halt
- 3. JVM Shutdown Hooks
- 3.1. Register Shutdown Hook
- 3.2. Unregister Shutdown Hook
- 4. When Do Hooks Run?
- 5. Exception Handling in Shutdown Hooks
- 6. Application Threads and Thread Pools
- 7. Summary
- JVM Shutdown Hook in Java
- 1. Introduction
- 2. Technologies used
- 3. Adding Hooks
- 4. JVM Shutdown Hook Simple Example
- 5. Removing a Shutdown Hook
- 6. Summary
- 7. Download the source code
JVM Shutdown Hook in Java
Shutdown Hooks are a special construct that allows developers to plug in a piece of code to be executed when the JVM is shutting down. This comes in handy in cases where we need to do special clean up operations in case the VM is shutting down.
Handling this using the general constructs such as making sure that we call a special procedure before the application exits (calling System.exit(0) ) will not work for situations where the VM is shutting down due to an external reason (ex. kill request from O/S), or due to a resource problem (out of memory). As we will see soon, shutdown hooks solve this problem easily, by allowing us to provide an arbitrary code block, which will be called by the JVM when it is shutting down.
From the surface, using a shutdown hook is downright straightforward. All we have to do is simply write a class that extends the java.lang.Thread class, and provide the logic that we want to perform when the VM is shutting down, inside the public void run() method. Then we register an instance of this class as a shutdown hook to the VM by calling Runtime.getRuntime().addShutdownHook(Thread) method. If you need to remove a previously registered shutdown hook, the Runtime class provides the removeShutdownHook(Thread) method as well.
Example 1 (Anonymous inner class):
Java
When we run the above code, you will see that the shutdown hook is getting called by the JVM when it finishes the execution of the main method.
Output:
Application Terminating . Shutdown Hook is running !
Java
2 X 1 = 2 2 X 2 = 4 2 X 3 = 6 2 X 4 = 8 2 X 5 = 10 2 X 6 = 12 2 X 7 = 14 2 X 8 = 16 2 X 9 = 18 2 X 10 = 20 In clean up code In shutdown hook
Guide to JVM Shutdown
In this tutorial, we’re going to investigate the details of the JVM shutdown. Firstly we’ll see in which conditions the JVM shuts down. Then we’ll focus on the shutdown hooks and see how they’re executed.
2. JVM Shutdown
The JVM shuts down either abruptly or normally. We’ll first cover the orderly shutdown.
2.1. Normal Shutdown by Thread Count
When there remains no non-daemon thread, the JVM shuts down normally. We can test this by writing a small main function:
public static void main(String[] args)
This code isn’t multithreaded and runs on a single thread, the main thread. When it prints «Hello world!», the main thread terminates. As a result, the JVM starts the shutdown process since the only existing thread has terminated.
We’ll next investigate the multi-threaded applications. When an application uses a thread pool, the pool manages the worker threads. So until the pool is terminated, the JVM doesn’t shut down based on the thread count:
public void runWithPool() < ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(() ->System.out.println("Hello world!")); System.out.println("Completing the method!"); >
In this example, we’re defining a thread pool of size ten. Then we’re executing a simple task printing «Hello world!«. When the method completes, the JVM continues to run. This is because the thread pool contains a worker thread.
Another important point is that the thread pool only starts a core thread when we submit a task. For example, Executors.newFixedThreadPool(10) doesn’t start ten threads right away. The pool reaches its desired core pool size after we submit ten tasks:
public void runWithPoolWithoutExecutingAnyTask()
Unlike the previous example, the JVM shuts down after the method completes since the pool contains zero worker threads.
Keep in mind that worker threads contain an internal loop that keeps them alive. When we start a Thread manually, it terminates after the task completes:
public void runWithThread() < new Thread(() ->System.out.println("Hello world!")).start(); System.out.println("Completing the method!"); >
Here, the runWithThread method runs on the main thread. The new thread starts and terminates in the current method. So when the main thread also terminates, the JVM shuts down.
So far we’ve used non-daemon threads. Next, we’ll start a daemon thread to execute a task:
public void runWithDaemonThread()
Here, daemonThread runs a task that loops forever. But since it’s a daemon thread, it doesn’t prevent the JVM from terminating.
2.2. Normal Shutdown with System.exit
System.exit also initiates a normal shutdown.
Here, when we invoke the System exit method, it terminates the JVM. Note that we’re passing 0 as the exit status. By convention, non-zero status codes represent abnormal termination.
Alternatively, we can invoke Runtime.getRuntime().exit(0) instead of System.exit(0). They’re effectively equivalent.
2.3. Normal Shutdown with CTRL-C
Pressing CTRL-C also initiates a normal shutdown. As we’ll see in a moment, shutdown hooks enable us to capture the shutdown attempt and act on it.
2.4. Abrupt Shutdown with System.halt
We’ll next terminate the JVM forcibly by invoking the System.halt method. This results in an abrupt shutdown where the JVM doesn’t run the shutdown hooks or finalizers:
In this method, after the halt invocation, the JVM terminates immediately.
3. JVM Shutdown Hooks
We’ll now talk about the JVM shutdown hooks. The hooks are initialized but not-started Thread instances. The JVM starts these threads when a normal shutdown is in progress. They’re mainly used to release the resources and do some cleanup.
3.1. Register Shutdown Hook
To register a shutdown hook, we must first create a thread. Then we must pass this thread to the Runtime.addShutdownHook method:
final Thread firstHook = new Thread(() -> System.out.println("First hook.")); Runtime.getRuntime().addShutdownHook(firstHook);
As the name implies, we can add multiple shutdown hooks.
3.2. Unregister Shutdown Hook
The hooks are registered by their object identities. So we can unregister a hook passing the same Thread instance to the removeShutdownHook method:
Runtime.getRuntime().removeShutdownHook(firstHook);
Note that we’re using the same Thread instance that was used for registration.
4. When Do Hooks Run?
The shutdown hooks only run during a normal shutdown. This includes the cases:
- when the last normal thread terminates
- when someone invokes System.exit
- when the Java process is interrupted — e.g. SIGINT
On a normal shutdown, the JVM starts all hook threads and they start running concurrently. We’ll now register some hooks:
public void runHooksOnExit() < final Thread firstHook = new Thread(() ->System.out.println("First hook.")); Runtime.getRuntime().addShutdownHook(firstHook); final Thread secondHook = new Thread(() -> System.out.println("Second hook.")); Runtime.getRuntime().addShutdownHook(secondHook); System.out.println("Exiting. "); System.exit(0); // Runtime.getRuntime().exit(status); >
Exiting. Second hook. First hook.
An important note is that a hook mustn’t depend on the execution order of others. If the execution order matters, a better option is merging all shutdown tasks into a single hook. This way we can guarantee the order of execution.
5. Exception Handling in Shutdown Hooks
Exception handling in a shutdown hook is similar to other threads. For example, we can register an UncaughtExceptionHandler instance to handle the uncaught exceptions:
public void exceptionHandlingInHooks() < final Thread hook = new Thread(() ->< throw new RuntimeException("Planned"); >); hook.setUncaughtExceptionHandler(new UncaughtExceptionHandler() < @Override public void uncaughtException(Thread t, Throwable e) < System.out.println("Exception: " + e.getMessage()); >>); Runtime.getRuntime().addShutdownHook(hook); System.exit(0); >
Here, we’re registering the handler via the setUncaughtExceptionHandler method.
6. Application Threads and Thread Pools
Lastly, we’ll investigate what happens to the application threads or thread pools during a shutdown. For example, we may have a crawler service with multiple threads backing it. Or we may have a ScheduledThreadPoolExecutor instance executing some scheduled tasks. During a shutdown, the JVM doesn’t try to stop or notify these application threads. They continue to run alongside the hook threads. In the end, they just terminate abruptly.
7. Summary
In this tutorial, we’ve learned that the JVM can shut down either normally or abruptly. We also examined the usage of shutdown hooks. Lastly, we saw that the JVM doesn’t attempt to stop application-owned threads.
As always the source code for all examples is available on Github.
JVM Shutdown Hook in Java
This article is a tutorial on implementing a simple JVM Shutdown Hook in Java. In this example, we will take a look at different ways we can terminate a JVM application.
1. Introduction
Shutdown Hooks allow developers to plug in the desired code to be executed when the JVM is shutting down. This is useful when we need to do special clean-up operations before the VM finishes terminating. 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. Also, Shutdown Hooks are also executed even when the VM is shutting down due to an external reason like a kill request from the O/S. The general methods such as System.exit(0) will only work if the VM is terminated by a controlled process.
2. Technologies used
3. Adding Hooks
In order to add a shutdown hook, we can use the Runtime.getRuntime().addShutdownHook() method: Adding Hook
Runtime.getRuntime().addShutdownHook(new Thread() < public void run()< System.out.println("Shutdown Hook running"); >>);
The way it works is that a created thread with the desired code to be executed is defined, and then we initialize it by adding it to the current runtime.
4. JVM Shutdown Hook Simple Example
class MyShutdownHookThread extends Thread < public void run() < System.out.println("Main terminated. We are in Shutdown Hook.\nBye!"); >> public class ShutdownHook < public static void main(String[] args) throws Exception < Thread shutdownHook = new MyShutdownHookThread(); Runtime.getRuntime().addShutdownHook(shutdownHook); System.out.println("Now main is running."); >>
- line 1: we create a new thread class that will actually be out Shutdown Hook.
- line 2: inside the method run(), we write the code we want to execute
- line 11: inside our main code, we initialize our hook bypassing the thread class we created as a variable in the addShutdownHook() method
5. Removing a Shutdown Hook
Java also gives as the ability to remove a shutdown hook if it is already defined by using the method Simple Example with Removing Hook
class RemovedShutdownHookThread extends Thread < public void run() < System.out.println("Main terminated. We are in Shutdown Hook.\nBye!"); >> public class RemoveShutdownHook < public static void main(String[] args) throws Exception < Thread shutdownHook = new RemovedShutdownHookThread(); Runtime.getRuntime().addShutdownHook(shutdownHook); System.out.println("Now main is running."); Runtime.getRuntime().removeShutdownHook(shutdownHook); >>
6. Summary
In these examples, we demonstrated how we can use the Shutdown Hook methods that Java provides us. As we noticed, even though we initialized the Shutdown Hook before the main code of our program, it ran after the program terminated. This is very helpful as it gives us flexibility and a safe way to run a specific part of code e.g memory clean up.
7. Download the source code
This was an example of how to create and remove a JVM Shutdown Hook in Java.