< prev index next >

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

Print this page

        

*** 29,47 **** import java.lang.ref.Cleaner.Cleanable; import java.lang.ref.ReferenceQueue; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.ThreadFactory; 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 { /** * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. */ private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null; --- 29,48 ---- import java.lang.ref.Cleaner.Cleanable; 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 { /** * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. */ private static Function<Cleaner, CleanerImpl> cleanerImplAccess = null;
*** 101,120 **** 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 PhantomCleanableRef(cleaner, cleaner, () -> {}); if (threadFactory == null) { threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); } // 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.setDaemon(true); thread.start(); } /** --- 102,121 ---- 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(); } // 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(); } /**
*** 126,136 **** * for which the object is reachable. * <p> * If the thread is a ManagedLocalsThread, the threadlocals * are erased before each cleanup */ ! private void run() { Thread t = Thread.currentThread(); InnocuousThread mlThread = (t instanceof InnocuousThread) ? (InnocuousThread) t : null; while (!phantomCleanableList.isListEmpty() || --- 127,138 ---- * for which the object is reachable. * <p> * 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() ||
*** 145,159 **** // due to a race with clear/clean Cleanable ref = (Cleanable) queue.remove(60 * 1000L); if (ref != null) { ref.clean(); } - } catch (InterruptedException i) { - continue; // ignore the interruption } catch (Throwable e) { // ignore exceptions from the cleanup action } } } /** * Perform cleaning on an unreachable PhantomReference. --- 147,180 ---- // 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) + } + } + } + + /** + * Processes next Cleanable that has been waiting in the queue. + * + * @return {@code true} if a Cleanable was found in the queue and + * was processed or {@code false} if the queue was empty. + */ + public boolean cleanNextPending() { + Cleanable ref = (Cleanable) queue.poll(); + if (ref != null) { + try { + ref.clean(); + } catch (Throwable t) { + // ignore exceptions from the cleanup action } + return true; + } else { + return false; } } /** * Perform cleaning on an unreachable PhantomReference.
*** 318,333 **** static ThreadFactory factory() { return factory; } public Thread newThread(Runnable r) { ! return AccessController.doPrivileged((PrivilegedAction<Thread>) () -> { Thread t = new InnocuousThread(r); t.setPriority(Thread.MAX_PRIORITY - 2); ! t.setName("Cleaner-" + t.getId()); return t; }); } } } --- 339,372 ---- static ThreadFactory factory() { return factory; } + final AtomicInteger cleanerThreadNumber = new AtomicInteger(); + public Thread newThread(Runnable r) { ! return AccessController.doPrivileged(new PrivilegedAction<Thread>() { ! @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<Cleaner> { + CleanerCleanable(Cleaner cleaner) { + super(cleaner, cleaner); + } + + @Override + protected void performCleanup() { + // no action + } + } }
< prev index next >