< prev index next >

src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java

Print this page

        

@@ -23,21 +23,22 @@
  * questions.
  */
 
 package jdk.internal.ref;
 
+import jdk.internal.misc.InnocuousThread;
+
 import java.lang.ref.Cleaner;
 import java.lang.ref.Cleaner.Cleanable;
+import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.function.Function;
 
-import jdk.internal.misc.InnocuousThread;
-
 /**
  * CleanerImpl manages a set of object references and corresponding cleaning actions.
  * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}.
  */
 public final class CleanerImpl implements Runnable {

@@ -46,19 +47,17 @@
      * An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
      */
     private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
 
     /**
-     * Heads of a CleanableList for each reference type.
+     * Head of the PhantomCleanableImpl list.
      */
-    final PhantomCleanable<?> phantomCleanableList;
-
-    final WeakCleanable<?> weakCleanableList;
-
-    final SoftCleanable<?> softCleanableList;
+    final PhantomCleanableImpl phantomCleanableList;
 
-    // The ReferenceQueue of pending cleaning actions
+    /**
+     * The ReferenceQueue of pending cleaning actions
+     */
     final ReferenceQueue<Object> queue;
 
     /**
      * Called by Cleaner static initialization to provide the function
      * to map from Cleaner to CleanerImpl.

@@ -84,13 +83,11 @@
     /**
      * Constructor for CleanerImpl.
      */
     public CleanerImpl() {
         queue = new ReferenceQueue<>();
-        phantomCleanableList = new PhantomCleanableRef();
-        weakCleanableList = new WeakCleanableRef();
-        softCleanableList = new SoftCleanableRef();
+        phantomCleanableList = new PhantomCleanableImpl();
     }
 
     /**
      * Starts the Cleaner implementation.
      * Ensure this is the CleanerImpl for the Cleaner.

@@ -100,13 +97,13 @@
      */
     public void start(Cleaner cleaner, ThreadFactory threadFactory) {
         if (getCleanerImpl(cleaner) != this) {
             throw new AssertionError("wrong cleaner");
         }
-        // schedule a nop cleaning action for the cleaner, so the associated thread
-        // will continue to run at least until the cleaner is reclaimable.
-        new CleanerCleanable(cleaner);
+        // schedule a no-op cleaning action for the cleaner, so the associated
+        // thread will continue to run at least until the cleaner is reclaimable.
+        new PhantomCleanableImpl(cleaner, cleaner, null);
 
         if (threadFactory == null) {
             threadFactory = CleanerImpl.InnocuousThreadFactory.factory();
         }
 

@@ -133,13 +130,11 @@
     public void run() {
         Thread t = Thread.currentThread();
         InnocuousThread mlThread = (t instanceof InnocuousThread)
                 ? (InnocuousThread) t
                 : null;
-        while (!phantomCleanableList.isListEmpty() ||
-                !weakCleanableList.isListEmpty() ||
-                !softCleanableList.isListEmpty()) {
+        while (!phantomCleanableList.isListEmpty()) {
             if (mlThread != null) {
                 // Clear the thread locals
                 mlThread.eraseThreadLocals();
             }
             try {

@@ -155,89 +150,112 @@
             }
         }
     }
 
     /**
-     * Perform cleaning on an unreachable PhantomReference.
+     * Perform cleaning on an unreachable PhantomCleanable's referent.
+     */
+    public static final class PhantomCleanableImpl extends PhantomCleanable<Object> {
+
+        /**
+         * The list of PhantomCleanableImpl; synchronizes insert and remove.
+         */
+        private final PhantomCleanableImpl list;
+
+        /**
+         * The cleanup action.
      */
-    public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
         private final Runnable action;
 
         /**
-         * Constructor for a phantom cleanable reference.
+         * Links to previous and next in a doubly-linked list.
+         */
+        private PhantomCleanableImpl prev = this, next = this;
+
+        /**
+         * Constructor for a PhantomCleanableImpl.
          * @param obj the object to monitor
          * @param cleaner the cleaner
-         * @param action the action Runnable
+         * @param action the action Runnable (or null if no-op)
          */
-        public PhantomCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
+        public PhantomCleanableImpl(Object obj, Cleaner cleaner, Runnable action) {
             super(obj, cleaner);
+            this.list = CleanerImpl.getCleanerImpl(cleaner).phantomCleanableList;
             this.action = action;
+            // register this PhantomCleanableImpl instance so it remains strongly
+            // reachable until cleaned
+            insert();
+            // ensure obj and cleaner remain strongly reachable at least until
+            // this PhantomCleanableImpl is registered
+            Reference.reachabilityFence(obj);
+            Reference.reachabilityFence(cleaner);
         }
 
         /**
          * Constructor used only for root of phantom cleanable list.
          */
-        PhantomCleanableRef() {
+        PhantomCleanableImpl() {
             super();
+            this.list = this;
             this.action = null;
         }
 
-        @Override
-        protected void performCleanup() {
-            action.run();
-        }
-
         /**
-         * Prevent access to referent even when it is still alive.
-         *
-         * @throws UnsupportedOperationException always
+         * Insert this PhantomCleanableImpl after the list head.
          */
-        @Override
-        public Object get() {
-            throw new UnsupportedOperationException("get");
+        private void insert() {
+            synchronized (list) {
+                prev = list;
+                next = list.next;
+                next.prev = this;
+                list.next = this;
+            }
         }
 
         /**
-         * Direct clearing of the referent is not supported.
+         * Remove this PhantomCleanableImpl from the list.
          *
-         * @throws UnsupportedOperationException always
+         * @return true if Cleanable was removed or false if not because
+         * it had already been removed before
          */
-        @Override
-        public void clear() {
-            throw new UnsupportedOperationException("clear");
+        private boolean remove() {
+            synchronized (list) {
+                if (next != this) {
+                    next.prev = prev;
+                    prev.next = next;
+                    prev = this;
+                    next = this;
+                    return true;
+                }
+                return false;
         }
     }
 
     /**
-     * Perform cleaning on an unreachable WeakReference.
-     */
-    public static final class WeakCleanableRef extends WeakCleanable<Object> {
-        private final Runnable action;
-
-        /**
-         * Constructor for a weak cleanable reference.
-         * @param obj the object to monitor
-         * @param cleaner the cleaner
-         * @param action the action Runnable
+         * Returns true if the list's next reference refers to itself.
+         *
+         * @return true if the list is empty
          */
-        WeakCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
-            super(obj, cleaner);
-            this.action = action;
+        boolean isListEmpty() {
+            synchronized (list) {
+                return list == list.next;
+            }
         }
 
         /**
-         * Constructor used only for root of weak cleanable list.
+         * Unregister this PhantomCleanableImpl and invoke cleanup action,
+         * ensuring at-most-once semantics.
          */
-        WeakCleanableRef() {
-            super();
-            this.action = null;
-        }
-
         @Override
-        protected void performCleanup() {
+        public final void clean() {
+            if (remove()) {
+                super.clear();
+                if (action != null) {
             action.run();
         }
+            }
+        }
 
         /**
          * Prevent access to referent even when it is still alive.
          *
          * @throws UnsupportedOperationException always

@@ -254,62 +272,34 @@
          */
         @Override
         public void clear() {
             throw new UnsupportedOperationException("clear");
         }
-    }
-
-    /**
-     * Perform cleaning on an unreachable SoftReference.
-     */
-    public static final class SoftCleanableRef extends SoftCleanable<Object> {
-        private final Runnable action;
-
-        /**
-         * Constructor for a soft cleanable reference.
-         * @param obj the object to monitor
-         * @param cleaner the cleaner
-         * @param action the action Runnable
-         */
-        SoftCleanableRef(Object obj, Cleaner cleaner, Runnable action) {
-            super(obj, cleaner);
-            this.action = action;
-        }
-
-        /**
-         * Constructor used only for root of soft cleanable list.
-         */
-        SoftCleanableRef() {
-            super();
-            this.action = null;
-        }
-
-        @Override
-        protected void performCleanup() {
-            action.run();
-        }
 
         /**
-         * Prevent access to referent even when it is still alive.
+         * This method always throws {@link UnsupportedOperationException}.
+         * Enqueuing details of {@link Cleaner.Cleanable}
+         * are a private implementation detail.
          *
          * @throws UnsupportedOperationException always
          */
         @Override
-        public Object get() {
-            throw new UnsupportedOperationException("get");
+        public final boolean isEnqueued() {
+            throw new UnsupportedOperationException("isEnqueued");
         }
 
         /**
-         * Direct clearing of the referent is not supported.
+         * This method always throws {@link UnsupportedOperationException}.
+         * Enqueuing details of {@link Cleaner.Cleanable}
+         * are a private implementation detail.
          *
          * @throws UnsupportedOperationException always
          */
         @Override
-        public void clear() {
-            throw new UnsupportedOperationException("clear");
+        public final boolean enqueue() {
+            throw new UnsupportedOperationException("enqueue");
         }
-
     }
 
     /**
      * A ThreadFactory for InnocuousThreads.
      * The factory is a singleton.

@@ -333,20 +323,6 @@
                     return t;
                 }
             });
         }
     }
-
-    /**
-     * A PhantomCleanable implementation for tracking the Cleaner itself.
-     */
-    static final class CleanerCleanable extends PhantomCleanable<Cleaner> {
-        CleanerCleanable(Cleaner cleaner) {
-            super(cleaner, cleaner);
-        }
-
-        @Override
-        protected void performCleanup() {
-            // no action
-        }
-    }
 }
< prev index next >