Principle resolution of reference queue correlation for managed resources in Java

  • 2020-04-01 04:32:36
  • OfStack

When an object changes its reachability state, references to that object may be placed in the reference queue. These queues are used by the garbage collector to communicate with our code about changes in object accessibility. These queues are the best way to detect accessibility changes, although we can also detect object accessibility changes by checking whether the return value of the get method is null.

Reference objects can be associated with a particular queue when constructed. Each subclass of Reference provides a constructor in the following form:

.public Strength Reference (T referent, ReferenceQueueq): this method creates a new Reference object with the given Reference object and registers the Reference object in the given queue. Weak and soft references are inserted into the queue after the garbage collector determines that their referential objects are in the specific accessibility state they represent, and both references are cleared before they are inserted into the queue. Virtual references are also inserted into the queue after the garbage collector determines that its referent objects are in the virtual reachable state, but they are not cleared. Once a reference object is inserted into the queue by the garbage collector, the return value of its get method is definitely null, so the object can never be resurrected.

Registering a reference object in a reference queue does not create a reference between the queue and the reference object. If our reference object itself becomes unreachable, then it cannot be queued. Therefore, our application needs to keep strong references to all reference objects.

The ReferenceQueue class provides three methods for removing references from a queue:

The public Reference < The & # 63; Extends the > Poll (): to remove and return the next reference object in the queue, or null if the queue is empty. .public Referenceremove ()throw InterruptedException: used to remove and return the next reference object in the queue, which blocks until the queue returns the available reference object. Public Referenceremove (long timeout) throws interrupte-dexception: used to remove and return the next reference object in the queue. This method either blocks until the queue returns the available reference object, or ends when the specified timeout is exceeded. If the specified timeout is exceeded, null is returned. If the specified timeout is 0, it means that the wait will continue indefinitely.

The poll method allows threads to query whether a reference is in the queue and perform specific actions when the reference is in the queue. The remove method can handle more complex (and less common) situations, where a dedicated thread is responsible for removing the reference from the queue and performing the appropriate action. The blocking behavior of these methods is the same as that defined in object.wait. For a particular reference, we can query whether it is in the queue by its isEnqueued method, or we can force it into the queue by calling its enqueue method, but this is usually done by the garbage collector.

A virtual reference in a reference queue can be used to determine when an object can be reclaimed. We can't access by virtual reference any object, even if the object is accessible by other means of also is such, because of the virtual reference the get method always returns null, in fact, using virtual reference to look up to the recycling objects is the safest method, because of the weak and soft references in the object can be after the end will be inserted into the queue, and virtual reference is after the alleged object is end inserted into the queue, namely in the object can perform certain operations after the final moments of the plug people queue, so it is absolutely safe. You should always use a virtual reference if you can, because other references have the possibility of finalize methods using finalizable objects.

Consider the example of a resource manager that can control access to external resource collections. Objects can request access to an external resource and do so until the operation is complete, after which they should return the resource they used to the resource manager. If the resource is Shared, the right to use it is passed between multiple objects, and possibly even between multiple threads, making it difficult to determine which object is the last consumer of the resource, and thus which piece of code is responsible for returning the resource. To handle this, the resource manager can automatically recycle a resource by associating it with a special object called a key. As long as the key object is reachable, we assume that the resource is still in use; As long as the key object can be garbage collected, the resource is automatically freed. The following code is an abstract representation of the above resource:


  interface Resource{

  void use(Object key, Object ... args);

  void release();

  }

When a resource is acquired, its key object must be provided to the resource manager. For the returned Resource instance, the Resource can only be used if it has its corresponding key. This ensures that after the key is retrieved, the corresponding Resource cannot be used again, even though the Resource object representing the Resource itself may still be reachable. Note that the Resource object does not store a strong reference to the key object, which is important because it prevents the key object from becoming unreachable, causing the Resource to be unrecoverable. The Resource implementation can 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 IlleqalArgumentException("wrong key"

  //...use the resource

  }

  public synchronized void release(){

  if (needsRelease){

  needsRelease=false:

  //=release the resource

  }

  }

  }

The hash code for the key object is stored when the resource is created, and whenever the use method is called, it checks to see if the same key is provided. The actual use of resources may also require synchronization, but we omit them here for simplicity. The release method, which is responsible for releasing the resource, can be called by the consumer of the resource directly after use or by the resource manager when the key object is no longer referenced. Because we will use separate threads to monitor the reference queue, the release method must be synchronized and must allow multiple calls.

The actual resource management appliance has the following form:


  public final class ResourceManager{

  final ReferenceQueue

                                                       
The key object can be any object, which gives the resource consumer a lot of flexibility compared to having the resource manager assign the key object. When the getResource method is called, a new resource-worker MPL object is created and the key provided to the method is passed to the new ResourceImpl object. A virtual reference is then created, whose referential object is the key passed to the method, and the virtual reference is inserted into the resource manager's reference queue. The resulting virtual reference and reference objects are stored in a map table that serves two purposes: to keep all virtual reference objects reachable, and to provide a convenient way to query the actual Resource object associated with each virtual reference. Another way is to subclass PhantomReference and save the Resource object in a field.

If the key object becomes unreachable, the resource manager USES a separate reaper thread to process the resource. The shutdown method "closes" the resource manager by terminating the harvester thread in response to an interrupt, causing the getResource method to throw an ille-lllestateexception. In this simple design, any reference to the insert queue after the resource manager is closed is not processed. The actual harvester thread is as follows:


  class ReaperThread extends Thread{

  public void run(){

  //run until interrupted

  while (true){

  try{

  Reference ref=queue.remove();

  Resource res=null;

  synchronized(ResourceManager.this){

  res=refs.get(ref);

  refs . remove(ref);

  }

  res .release();

  ref.clear();

  }

  catch (InterruptedException ex){

  break;//all done

  }

  }

  }

  }

ReaperThread is an inner class, and a given harvester thread runs until the associated resource manager is shut down. The thread blocks on the remove method until the virtual reference associated with a particular key is inserted into the reference queue. The virtual reference can get a reference to the Resource object from the mapping table, and the key-reference pair will be removed from the mapping table. Next, call its release method on the Resource object to release the Resource. In the end,

The virtual reference is cleared so that the key can be reclaimed.

As an alternative to using separate threads, all operations that invoke the pollmethod on the reference queue and release all resources whose keys have become inaccessible can be replaced by the getResourc "method, shutdow" method, which can also be used to perform the final poll operation. The semantics of the resource manager will depend on the actual resource type and the pattern of resource usage.

A design that USES a reference queue is much more reliable than one that USES terminations directly (especially virtual references). But keep in mind that the exact time and place at which the reference object is inserted into the reference queue cannot be determined, nor can we determine whether all pluggable references are inserted into the reference queue when the application terminates. If we need to ensure that all resources are released before the application terminates, we must install the necessary closing hooks or use other protocols defined by the application to ensure this.


Related articles: