Class FinalizableReferenceQueue

  • All Implemented Interfaces:
    java.io.Closeable, java.lang.AutoCloseable

    public class FinalizableReferenceQueue
    extends java.lang.Object
    implements java.io.Closeable
    A reference queue with an associated background thread that dequeues references and invokes FinalizableReference.finalizeReferent() on them.

    Keep a strong reference to this object until all of the associated referents have been finalized. If this object is garbage collected earlier, the backing thread will not invoke finalizeReferent() on the remaining references.

    As an example of how this is used, imagine you have a class MyServer that creates a ServerSocket, and you would like to ensure that the ServerSocket is closed even if the MyServer object is garbage-collected without calling its close method. You could use a finalizer to accomplish this, but that has a number of well-known problems. Here is how you might use this class instead:

    
     public class MyServer implements Closeable {
       private static final FinalizableReferenceQueue frq = new FinalizableReferenceQueue();
       // You might also share this between several objects.
    
       private static final Set<Reference<?>> references = Sets.newConcurrentHashSet();
       // This ensures that the FinalizablePhantomReference itself is not garbage-collected.
    
       private final ServerSocket serverSocket;
    
       private MyServer(...) {
         ...
         this.serverSocket = new ServerSocket(...);
         ...
       }
    
       public static MyServer create(...) {
         MyServer myServer = new MyServer(...);
         final ServerSocket serverSocket = myServer.serverSocket;
         Reference<?> reference = new FinalizablePhantomReference<MyServer>(myServer, frq) {
           public void finalizeReferent() {
             references.remove(this):
             if (!serverSocket.isClosed()) {
               ...log a message about how nobody called close()...
               try {
                 serverSocket.close();
               } catch (IOException e) {
                 ...
               }
             }
           }
         };
         references.add(reference);
         return myServer;
       }
    
       public void close() {
         serverSocket.close();
       }
     }
     
    Since:
    2.0
    • Field Detail

      • logger

        private static final java.util.logging.Logger logger
      • FINALIZER_CLASS_NAME

        private static final java.lang.String FINALIZER_CLASS_NAME
        See Also:
        Constant Field Values
      • startFinalizer

        private static final java.lang.reflect.Method startFinalizer
        Reference to Finalizer.startFinalizer().
      • queue

        final java.lang.ref.ReferenceQueue<java.lang.Object> queue
        The actual reference queue that our background thread will poll.
      • frqRef

        final java.lang.ref.PhantomReference<java.lang.Object> frqRef
      • threadStarted

        final boolean threadStarted
        Whether or not the background thread started successfully.
    • Constructor Detail

      • FinalizableReferenceQueue

        public FinalizableReferenceQueue()
        Constructs a new queue.
    • Method Detail

      • close

        public void close()
        Specified by:
        close in interface java.lang.AutoCloseable
        Specified by:
        close in interface java.io.Closeable
      • cleanUp

        void cleanUp()
        Repeatedly dequeues references from the queue and invokes FinalizableReference.finalizeReferent() on them until the queue is empty. This method is a no-op if the background thread was created successfully.
      • loadFinalizer

        private static java.lang.Class<?> loadFinalizer​(FinalizableReferenceQueue.FinalizerLoader... loaders)
        Iterates through the given loaders until it finds one that can load Finalizer.
        Returns:
        Finalizer.class
      • getStartFinalizer

        static java.lang.reflect.Method getStartFinalizer​(java.lang.Class<?> finalizer)
        Looks up Finalizer.startFinalizer().