--- old/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-05-15 22:37:38.344944778 +0200 +++ new/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-05-15 22:37:38.207947136 +0200 @@ -25,8 +25,11 @@ 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; @@ -34,8 +37,6 @@ 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}. @@ -48,15 +49,13 @@ private static Function 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 queue; /** @@ -86,9 +85,7 @@ */ public CleanerImpl() { queue = new ReferenceQueue<>(); - phantomCleanableList = new PhantomCleanableRef(); - weakCleanableList = new WeakCleanableRef(); - softCleanableList = new SoftCleanableRef(); + phantomCleanableList = new PhantomCleanableImpl(); } /** @@ -102,9 +99,9 @@ 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(); @@ -135,9 +132,7 @@ 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(); @@ -157,84 +152,107 @@ } /** - * Perform cleaning on an unreachable PhantomReference. + * Perform cleaning on an unreachable PhantomCleanable's referent. */ - public static final class PhantomCleanableRef extends PhantomCleanable { + public static final class PhantomCleanableImpl extends PhantomCleanable { + + /** + * The list of PhantomCleanableImpl; synchronizes insert and remove. + */ + private final PhantomCleanableImpl list; + + /** + * The cleanup action. + */ 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 { - 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() { - action.run(); + public final void clean() { + if (remove()) { + super.clear(); + if (action != null) { + action.run(); + } + } } /** @@ -256,58 +274,30 @@ public void clear() { throw new UnsupportedOperationException("clear"); } - } - - /** - * Perform cleaning on an unreachable SoftReference. - */ - public static final class SoftCleanableRef extends SoftCleanable { - 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"); } - } /** @@ -335,18 +325,4 @@ }); } } - - /** - * A PhantomCleanable implementation for tracking the Cleaner itself. - */ - static final class CleanerCleanable extends PhantomCleanable { - CleanerCleanable(Cleaner cleaner) { - super(cleaner, cleaner); - } - - @Override - protected void performCleanup() { - // no action - } - } }