THE Java™ Programming Language, Fourth Edition

(Jeff_L) #1

determine which piece of code is responsible for returning the resource. To deal with this situation, the
resource manager can automate the recovery of the resource by associating with it a special object called the
key. As long as the key object is reachable, the resource is considered in use. As soon as the key object can be
reclaimed, the resource is automatically released. Here's an abstract representation of such a resource:


interface Resource {
void use(Object key, Object... args);
void release();
}


When a resource is obtained, a key must be presented to the resource manager. The Resource instance that
is given back will only allow use of the resource when presented with that key. This ensures that the resource
cannot be used after the key has been reclaimed, even though the Resource object itself may still be
reachable. Note that it is important that the Resource object not store a strong reference to the key object,
since that would prevent the key from ever becoming unreachable, and so the resource could never be
recovered. A Resource implementation class might be nested in the resource manager:


private static class ResourceImpl implements Resource {
int keyHash;
boolean needsRelease = false;


ResourceImpl(Object key) {
keyHash = System.identityHashCode(key);


// .. set up the external resource


needsRelease = true;
}


public void use(Object key, Object... args) {
if (System.identityHashCode(key) != keyHash)
throw new IllegalArgumentException("wrong key");


// ... use the resource ...
}


public synchronized void release() {
if (needsRelease) {
needsRelease = false;


// .. release the resource ...
}
}
}


When the resource is created it stores the identity hash code of the key, and whenever use is called, it checks
that the same key was provided. Actually using the resource may require additional synchronization, but for
simplicity this is elided. The release method is responsible for releasing the resource. It can either be
called directly by the users of the resource when they have finished, or it will be called through the resource
manager when the key object is no longer referenced. Because we will be using a separate thread to watch the
reference queue, release has to be synchronized and it has to be tolerant to being called more than
once.


The actual resource manager looks like this:


public final class ResourceManager {

Free download pdf