Shutdown hook - How to regularly stop Java application

Basically every java application is terminated when end of main method is reached or when all running threads run out of code. Find more information about stopping threads (here).

It is possible to force java application to terminate immediately with simple method call:

System.exit(0);

This method can be called anytime from within the code (eg. when user clicks 'Quit' button or in case of fatal errors). JVM is terminated immediately. As a consequence all data in application is lost - objects are gone, opened connections might hang in some weird state...

On Linux systems java application can be terminated from console window in the same way as any other process - kill the process. Before executing kill command you need to know the process id (PID) of your java application. This can be done in many ways. Example (PID is colored with red):

> ps -ef | grep java
501
346 242 0 0:00.04 ttys000 0:00.13 /usr/bin/java -jar javaShutdownHook.jar
501 348 254 0 0:00.00 ttys001 0:00.00 grep java

Process id can also be viewed by a tool jps which is part of JDK instalation (not JRE).

> jps -ml
346 javaShutdownHook.jar
349 sun.tools.jps.Jps -ml

Once you know the process id of process you want to terminate, simply execute:

> kill 346

But how to regularly stop an application without any 'Quit' button? Services for example. Usually they don't have any GUI and the applications were meant to run forever in the background.

To stop an application in a regular manner you need to add ‘a shutdown hook’ to your java application. When kill command is executed, a special signal SIGTERM is sent to java process. The signal is intercepted by Runtime class (java.lang) which is the bond with the underlaying operating system, and consequently start the shutdown procedure.

A shutdown hook is a simple Thread object. The developer should implement the shutdown procedure within the run() method. Pass the Thread to the Runtime object by calling addShutdownHook(Thread t) method. When SIGTERM signal is received, Runtime class will start the thread.

Let’s try shutdown hook in action. This is the scenario: make a simple loop with counter which is increased every second (imagine this is a service). Then make a thread which will set the running flag to false and therefore exit the counter loop - then the application will reach end of main method in regular way. At the beginning of application set the Thread as a shutdown hook.

Remember: don't call start() method to run the Thread - Runtime class will do it!

Test class with main method:

public class StopTest {

public static boolean running = true;

public static void main(String[] args) {

System.out.println("+++ JavaStopTest started +++");

Runtime.getRuntime().addShutdownHook(new MyShutdownHook());

int i = 0;
while (running) {
System.out.println("count=" + i);
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (i == 100) {
// emergency exit
running = false;
}
}

System.out.println("--- JavaStopTest ended ---");
}

}

Thread - shutdown hook:

public class MyShutdownHook extends Thread {

@Override
public void run() {
System.out.println("=== my shutdown hook activated");

// stop running threads
// store data to DB
// close connection to DB
// disconnect...
// release other resources...

StopTest.running = false;

}

}

Build and run the code (from console) - you should see counter running. Open another console window, search for the PID of java process and kill the process (you have 100 seconds). Download already built jar (here).

Running example in two consoles:

CONSOLE 1:						CONSOLE 2:

# start application
> java -jar javaShutdownHook.jar

+++ StopTest started +++
count=0
count=1
count=2
count=3
...
							# get PID 
							> jps -ml
							7096 javaShutdownHook.jar
							# stop application
							> kill 7096
...
count=51
count=52
=== shutdown hook activated
# application is stopped
				

Overriding shutdown hook

A shutdown hook is not executed if java process is terminated with:

kill -9 <pid>

Kill level 9 sends more effective termination signal (SIGKILL), which terminates the application immediately without running the shutdown hook.

The same happens when the system is going to reboot or shutdown. First a SIGTERM signal is sent to all processes. Then the system waits for applications to terminate regularly. If applications fail to terminate after some time, SIGKILL signal is sent to force quit an application.