Saturday 12 April 2008

How to run code when your Java program is being terminated? Use ShutdownHook!

The starting point for this was a problem I have at work, where we have a program that is using ScheduledExecutorService, and is meant to run continuously, but we also want to run some code when the program is terminated with Ctrl-C or a 'kill' command.

At first, I thought that a try-finally would give me what I wanted. A little bit of testing proved me wrong. The try-finally structure can handle exceptions, and ensure that code enclosed in finally is called, but only in the case where the process is running normally, and not terminated externally. The statement inside a finally{} will not execute if the JVM is terminated.

The ShutdownHook is what I needed, which was added in JDK 1.3.1.  The method to use is Runtime.addShutdownHook().  The shutdown hook is pretty much any code you put inside the Thread.run() that you pass to this method.

public class FinallyTest {
public static void main(String[] args) {

final int thisNumber = 9;
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
System.out.println("I am now calling my shutdown stuff. EVERYTIME!");
System.out.println("This number: " + thisNumber);
}
});

try {
System.out.println("FinallyTest.main");
boolean loopIt = true;
int i = 0;
System.out.println("Now entering infinite loop.");
while (loopIt) {
i++;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}

} finally {
System.out.println("Finally has been called!");
}
}
}





Running the program, and then killing it gives me (this is on OS X, on an iMac):

krangsquared$ java -cp . FinallyTest &
[1] 5735
krangsquared$ FinallyTest.main
Now entering infinite loop.

Okay, we now have a process Id. Let's kill it! 


krangsquared$ kill 5735

krangsquared$ I am now calling my shutdown stuff. EVERYTIME!
This number: 9

[1]+ Exit 143 /System/Library/Frameworks/JavaVM.framework/Versions/1.6/Commands/java -cp . FinallyTest


The only catch to this is that this will not work if you terminate the program using "kill -9".  And I haven't checked this yet on Windows to see what happens if you kill it using TaskManager. (is there a "kill -9" equivalent on XP?)

Hope this helps someone out there! Or maybe someone who has a better idea or suggestion can make a comment. I need all the help I can get.  :)

Btw, I've found a blog post with a nicer way of doing this - instead of dumping a whole lot of stuff in a Thread.run() as an anonymous inner class (insert. closures. proposal. here.), have another Runnable inner class to contain all the shutdown code, then pass that in to the constructor of a new Thread that you pass to addShutdownHook().

No comments: