--- old/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-04-02 12:52:59.749641926 +0200 +++ new/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-04-02 12:52:59.638643849 +0200 @@ -25,133 +25,130 @@ package jdk.internal.ref; +import jdk.internal.misc.InnocuousThread; + import java.lang.ref.Cleaner; -import java.lang.ref.Cleaner.Cleanable; import java.lang.ref.ReferenceQueue; import java.security.AccessController; import java.security.PrivilegedAction; +import java.util.Objects; 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}. + * CleanerImpl is the implementation of {@link Cleaner}. */ -public final class CleanerImpl implements Runnable { - - /** - * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. - */ - private static Function cleanerImplAccess = null; - - /** - * Heads of a CleanableList for each reference type. - */ - final PhantomCleanable phantomCleanableList; - - final WeakCleanable weakCleanableList; - - final SoftCleanable softCleanableList; +public class CleanerImpl implements Cleaner { - // The ReferenceQueue of pending cleaning actions - final ReferenceQueue queue; + final Task task; - /** - * Called by Cleaner static initialization to provide the function - * to map from Cleaner to CleanerImpl. - * @param access a function to map from Cleaner to CleanerImpl - */ - public static void setCleanerImplAccess(Function access) { - if (cleanerImplAccess == null) { - cleanerImplAccess = access; - } else { - throw new InternalError("cleanerImplAccess"); - } + public CleanerImpl(ThreadFactory threadFactory) { + task = new Task(); + task.start(this, threadFactory); } - /** - * Called to get the CleanerImpl for a Cleaner. - * @param cleaner the cleaner - * @return the corresponding CleanerImpl - */ - static CleanerImpl getCleanerImpl(Cleaner cleaner) { - return cleanerImplAccess.apply(cleaner); - } - - /** - * Constructor for CleanerImpl. - */ - public CleanerImpl() { - queue = new ReferenceQueue<>(); - phantomCleanableList = new PhantomCleanableRef(); - weakCleanableList = new WeakCleanableRef(); - softCleanableList = new SoftCleanableRef(); + @Override + public Cleanable register(Object obj, Runnable action) { + Objects.requireNonNull(obj, "obj"); + Objects.requireNonNull(action, "action"); + return new CleanerImpl.PhantomCleanableRef(obj, this, action); } - /** - * Starts the Cleaner implementation. - * Ensure this is the CleanerImpl for the Cleaner. - * When started waits for Cleanables to be queued. - * @param cleaner the cleaner - * @param threadFactory the thread factory - */ - 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); - - if (threadFactory == null) { - threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); + // package-private access to Task's state + PhantomCleanable phantomCleanableList() { return task.phantomCleanableList; } + WeakCleanable weakCleanableList() { return task.weakCleanableList; } + SoftCleanable softCleanableList() { return task.softCleanableList; } + ReferenceQueue queue() { return task.queue; } + + /** + * CleanerImpl.Task manages a set of object references and corresponding + * cleaning actions and executes them after they are enqueued. + */ + private static final class Task implements Runnable { + /** + * Heads of a CleanableList for each reference type. + */ + final PhantomCleanable phantomCleanableList; + + final WeakCleanable weakCleanableList; + + final SoftCleanable softCleanableList; + + // The ReferenceQueue of pending cleaning actions + final ReferenceQueue queue; + + /** + * Constructor for Task. + */ + Task() { + queue = new ReferenceQueue<>(); + phantomCleanableList = new PhantomCleanableRef(); + weakCleanableList = new WeakCleanableRef(); + softCleanableList = new SoftCleanableRef(); } - // now that there's at least one cleaning action, for the cleaner, - // we can start the associated thread, which runs until - // all cleaning actions have been run. - Thread thread = threadFactory.newThread(this); - thread.setDaemon(true); - thread.start(); - } + /** + * Starts the Cleaner implementation. + * Ensure this is the CleanerImpl for the Cleaner. + * When started waits for Cleanables to be queued. + * @param cleaner the cleaner + * @param threadFactory the thread factory + */ + void start(CleanerImpl cleaner, ThreadFactory threadFactory) { + if (cleaner.task != 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); - /** - * Process queued Cleanables as long as the cleanable lists are not empty. - * A Cleanable is in one of the lists for each Object and for the Cleaner - * itself. - * Terminates when the Cleaner is no longer reachable and - * has been cleaned and there are no more Cleanable instances - * for which the object is reachable. - *

- * If the thread is a ManagedLocalsThread, the threadlocals - * are erased before each cleanup - */ - @Override - public void run() { - Thread t = Thread.currentThread(); - InnocuousThread mlThread = (t instanceof InnocuousThread) - ? (InnocuousThread) t - : null; - while (!phantomCleanableList.isListEmpty() || - !weakCleanableList.isListEmpty() || - !softCleanableList.isListEmpty()) { - if (mlThread != null) { - // Clear the thread locals - mlThread.eraseThreadLocals(); + if (threadFactory == null) { + threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); } - try { - // Wait for a Ref, with a timeout to avoid getting hung - // due to a race with clear/clean - Cleanable ref = (Cleanable) queue.remove(60 * 1000L); - if (ref != null) { - ref.clean(); + + // now that there's at least one cleaning action, for the cleaner, + // we can start the associated thread, which runs until + // all cleaning actions have been run. + Thread thread = threadFactory.newThread(this); + thread.setDaemon(true); + thread.start(); + } + + /** + * Process queued Cleanables as long as the cleanable lists are not empty. + * A Cleanable is in one of the lists for each Object and for the Cleaner + * itself. + * Terminates when the Cleaner is no longer reachable and + * has been cleaned and there are no more Cleanable instances + * for which the object is reachable. + *

+ * If the thread is a ManagedLocalsThread, the threadlocals + * are erased before each cleanup + */ + @Override + public void run() { + Thread t = Thread.currentThread(); + InnocuousThread mlThread = (t instanceof InnocuousThread) + ? (InnocuousThread) t + : null; + while (!phantomCleanableList.isListEmpty() || + !weakCleanableList.isListEmpty() || + !softCleanableList.isListEmpty()) { + if (mlThread != null) { + // Clear the thread locals + mlThread.eraseThreadLocals(); + } + try { + // Wait for a Ref, with a timeout to avoid getting hung + // due to a race with clear/clean + Cleanable ref = (Cleanable) queue.remove(60 * 1000L); + if (ref != null) { + ref.clean(); + } + } catch (Throwable e) { + // ignore exceptions from the cleanup action + // (including interruption of cleanup thread) } - } catch (Throwable e) { - // ignore exceptions from the cleanup action - // (including interruption of cleanup thread) } } }