break; // all done
}
}
}
}
ReaperThread is an inner class, and a given reaper thread runs until its associated resource manager is shut
down. It blocks on remove until a phantom reference associated with a particular key has been enqueued.
The phantom reference is used to get a reference to the Resource object from the map, and then that entry is
removed from the map. The Resource object then has release invoked on it to release the resource.
Finally, the phantom reference is cleared so that the key can actually be reclaimed.
As an alternative to using a separate thread, the getresource method could instead poll the queue
whenever it is called and release any resources whose key has become unreachable. The shutdown method
could then do a final poll, too. The semantics for the resource manager necessarily depend on the actual kind
of resource and its usage patterns.
A design that uses reference queues can be more reliable than direct use of finalizationparticularly with
phantom referencesbut remember that there are no guarantees as to exactly when or in what order a reference
object will be enqueued. There are also no guarantees that by the time an application terminates, all
enqueuable reference objects will have been enqueued. If you need to guarantee that all resources are released
before the application terminates, you must install the necessary shutdown hooks (see "Shutdown" on page
672) or other application-defined protocols to ensure this happens.
Exercise 17.3: Rework the resource implementation class so that it uses a reference object to keep track of the
key instead of using the hash code.
Exercise 17.4: Modify the reaper thread so that it stays alive after shutdown until all the allocated resources
can be released.
Exercise 17.5: Redesign the resource manager to not use a reaper thread. Be clear on what semantics the
resource manager has and on when resources will be released.
17.5.4. Finalization and Reachability
An object becomes finalizable when it becomes weakly reachable (or less). It would seem that to determine
reachability you need simply examine the source code for your applications. Unfortunately, such an
examination would often be wrong. Reachability is not determined by the statements in your source code, but
by the actual state of the virtual machine at runtime. The virtual machine can perform certain optimizations
that make an object unreachable much sooner than a simple examination of the source code would indicate.
For example, suppose a method creates an object that controls an external resource and that the only reference
is through a local variable. The method then uses the external resource and finally nulls the local reference or
simply returns, allowing the object to be finalized and release the external resource. The programmer might
assume that the object is reachable until that reference is set to null or the method returns. But the virtual
machine can detect that the object is not referenced within the method and may deem it unreachable and
finalizable the instant after it was constructed, causing immediate finalization and release of the resource,
which was not something the programmer intended. Even the reference queue designs that we have discussed
depend on the referent remaining reachable as long as the programmer expects it to be reachable.
The optimizations under consideration only apply to references held on the stackthat is, references stored in
local variables or parameters. If a reference is stored in a field, then the object remains reachable at least until