< 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 >