Java Cookbook, Second Edition
Problem
You want to have some action taken when your objects are removed from service. Solution
Use finalize( ) but don't trust it or write your own end-of-life method. Discussion
Developers coming from a C++ background tend to form a mental map that has a line of equivalency drawn from C++ destructors to Java finalizers. In C++, destructors are called automatically when you delete an object. Java, though, has no such operator as delete; objects are freed automatically by a part of the Java runtime called the garbage collector, or GC. GC runs as a background thread in Java processes and looks around every so often to see if any objects are no longer referred to by any reference variable. When it runs, as it frees objects, it calls their finalize( ) methods. For example, what if you (or some code you called) invoke System.exit( ) ? In this case, the entire JVM would cease to exist (assuming there isn't a security manager that denies your program permission to do so), and the finalizer is never run. Similarly, a "memory leak," or mistakenly held reference to your object, also prevents finalizers from running. Can't you just ensure that all finalizers get run simply by calling System.runFinalizersOnExit(true) ? Not really! This method is deprecated (see Recipe 1.9); the documentation notes: This method is inherently unsafe. It may result in finalizers being called on live objects while other threads are concurrently manipulating those objects, resulting in erratic behavior or deadlock. So what if you need some kind of cleanup? You must take responsibility for defining a method and invoking it before you let any object of that class go out of reference. You might call such a method cleanUp( ). JDK 1.3 introduced the runtime method addShutdownHook( ) , to which you pass a nonstarted Thread subclass object; if the virtual machine has a chance, it runs your shutdown hook code as part of termination. This normally works, unless the VM was terminated abruptly as by a kill signal on Unix or a KillProcess on Win32, or the VM aborts due to detecting internal corruption of its data structures. Program ShutdownDemo shown in Example 9-1 contains both a finalize( ) method and a shutdown hook. The program normally exits while holding a reference to the object with the finalize method. If run with -f as an argument, it "frees" the object and "forces" a GC run by calling System.gc( ) ; only in this case does the finalize( ) method run. The shutdown hook is run in every case. Example 9-1. Shutdown Demo
/** Demonstrate how finalize( ) methods and shutdownHooks interact * with calls to System.exit( ). */ public class ShutdownDemo { public static void main(String[] args) throws Exception { // Create an Object with a finalize( ) method. Object f = new Object( ) { public void finalize( ) { System.out.println( "Running finalize( )"); } }; // Add a shutdownHook to the JVM Runtime.getRuntime( ).addShutdownHook(new Thread( ) { public void run( ) { System.out.println("Running Shutdown Hook"); } }); // Unless the user puts -f (for "free") on the command line, // call System.exit while holding a reference to // Object f, which can therefore not be finalized( ). if (args.length == 1 && args[0].equals("-f")) { f = null; System.gc( ); } System.out.println("Calling System.exit( )"); System.exit(0); } } The bottom line? There's no guarantee, but finalizers and shutdown hooks both have pretty good odds of being run. |