--- old/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-02-16 16:37:13.757844524 +0100 +++ new/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-02-16 16:37:13.677844055 +0100 @@ -31,6 +31,7 @@ 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; @@ -39,7 +40,7 @@ * 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 { +public final class CleanerImpl implements Runnable { /** * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. @@ -76,7 +77,7 @@ * @param cleaner the cleaner * @return the corresponding CleanerImpl */ - static CleanerImpl getCleanerImpl(Cleaner cleaner) { + public static CleanerImpl getCleanerImpl(Cleaner cleaner) { return cleanerImplAccess.apply(cleaner); } @@ -103,7 +104,7 @@ } // schedule a nop cleaning action for the cleaner, so the associated thread // will continue to run at least until the cleaner is reclaimable. - new PhantomCleanableRef(cleaner, cleaner, () -> {}); + new CleanerCleanable(cleaner); if (threadFactory == null) { threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); @@ -112,7 +113,7 @@ // 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::run); + Thread thread = threadFactory.newThread(this); thread.setDaemon(true); thread.start(); } @@ -128,7 +129,8 @@ * If the thread is a ManagedLocalsThread, the threadlocals * are erased before each cleanup */ - private void run() { + @Override + public void run() { Thread t = Thread.currentThread(); InnocuousThread mlThread = (t instanceof InnocuousThread) ? (InnocuousThread) t @@ -147,15 +149,34 @@ if (ref != null) { ref.clean(); } - } catch (InterruptedException i) { - continue; // ignore the interruption } catch (Throwable e) { // ignore exceptions from the cleanup action + // (including interruption of cleanup thread) } } } /** + * Processes all Cleanable(s) that have been waiting in the queue. + * + * @return {@code true} if any Cleanable was found in the queue and + * was processed or {@code false} if the queue was empty. + */ + public boolean drainQueue() { + boolean cleaned = false; + Cleanable ref; + while ((ref = (Cleanable) queue.poll()) != null) { + try { + ref.clean(); + } catch (Throwable t) { + // ignore exceptions from the cleanup action + } + cleaned = true; + } + return cleaned; + } + + /** * Perform cleaning on an unreachable PhantomReference. */ public static final class PhantomCleanableRef extends PhantomCleanable { @@ -320,14 +341,32 @@ return factory; } + final AtomicInteger cleanerThreadNumber = new AtomicInteger(); + public Thread newThread(Runnable r) { - return AccessController.doPrivileged((PrivilegedAction) () -> { - Thread t = new InnocuousThread(r); - t.setPriority(Thread.MAX_PRIORITY - 2); - t.setName("Cleaner-" + t.getId()); - return t; + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Thread run() { + Thread t = new InnocuousThread(r); + t.setPriority(Thread.MAX_PRIORITY - 2); + t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement()); + return t; + } }); } } + /** + * 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 + } + } }