USING SHUTDOWN HOOKS
These tips were developed using Java(tm) 2 SDK, Standard Edition,
v 1.3.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Suppose that you're writing an application, and you'd like to
gain control when the application shuts down. You might want
to do this in order to close files that are open, for example,
close a log file that the application has written to.
One way to gain control is simply to have a shutdown method that
you call before calling exit:
callShutdown();
System.exit(0);
This approach works if your application terminates only in one
place, that is, System.exit is called only one place, or if you
specify callShutdown everywhere that you exit. This approach also
requires that you catch all exceptions that are thrown, which
otherwise would terminate the program abnormally.
In JDK 1.3 there's another way to handle shutdown: using shutdown
hooks. A shutdown hook is an initialized thread that has not yet
been executed. In other words, a shutdown hook is an object of a
class derived from the Thread class, with a run method that is
called to perform whatever actions you want. You register this
object with the Java(tm) Virtual Machine (JVM)*.
Here's an example:
import java.io.*;
public class ShutdownDemo {
private FileWriter fw_log;
private BufferedWriter bw_log;
// constructor that opens the log file
public ShutdownDemo() throws IOException {
fw_log = new FileWriter("log.txt");
bw_log = new BufferedWriter(fw_log);
// register the shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
endApp();
}
});;
}
// do some application processing and write to the log file
public void processApp1() throws IOException {
bw_log.write("testing");
bw_log.newLine();
}
// do some application processing resulting in an exception
public void processApp2() {
throw new RuntimeException();
}
// close the log file
public void endApp() {
try {
bw_log.close();
}
catch (IOException e) {
System.err.println(e);
}
}
public static void main(String args[]) throws IOException {
// create an application object
ShutdownDemo demo = new ShutdownDemo();
// do some processing
demo.processApp1();
// do some more processing that results in an exception
demo.processApp2();
}
}
This application creates an instance of the ShutdownDemo class,
representing an application. The constructor for the class opens
a log file, using FileWriter and BufferedWriter.
ShutdownDemo then calls processApp1. In its processing, processApp1
writes an entry to the log file. Then processApp2 is called. It
throws an exception that is not caught by the application. Normally,
this exception would terminate the application; the log file
entry previously written would be lost because the output is sitting
in a buffer which has not been flushed to disk.
But in this demo the output is not lost. This is because the
application registers a shutdown hook by saying:
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
endApp();
}
});;
Notice the use of an anonymous inner class. Here an instance of an
unnamed class derived from Thread is created, and a run method that
calls endApp is defined for the class.
All of this means that when the application is about to terminate,
the JVM starts the thread representing by the passed-in thread
object. When the thread starts, the run method is called. The run
method calls endApp, which closes the log file. This flushes the
output buffer.
To underscore the effect of the shutdown hook, comment out the
addShutdownHook lines in ShutdownDemo. You'll see that the log
file is empty when the program terminates.
You can register multiple shutdown hooks. In this case, each thread
that represents a hook is started in an unspecified order, and the
various threads run simultaneously. You cannot register or
unregister a shutdown hook after the shutdown sequence has started.
Doing so results in an IllegalStateException.
Because shutdown hooks run as threads, you must use thread-safe
programming techniques. Otherwise you risk having threads interfere
with each other. Also, it's wise to design your application for
simple and fast shutdown processing. For example, you might run
into trouble if your application uses services during shutdown that
are themselves in the processing of being shut down.
There are cases where shutdown processing does not happen even if
you have registered shutdown hooks. One example is corrupted native
methods, for example, when you dereference a null pointer in C code.
This feature is somewhat similar to the atexit library function in
C/C++.
For further information about shutdown hooks, see:
http://java.sun.com/j2se/1.3/docs/guide/lang/enhancements.html#hooks.
|