< prev index next >
src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java
Print this page
@@ -23,21 +23,22 @@
* questions.
*/
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;
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 {
@@ -46,19 +47,17 @@
* An object to access the CleanerImpl from a Cleaner; set by Cleaner init.
*/
private static Function<Cleaner, CleanerImpl> 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<Object> queue;
/**
* Called by Cleaner static initialization to provide the function
* to map from Cleaner to CleanerImpl.
@@ -84,13 +83,11 @@
/**
* Constructor for CleanerImpl.
*/
public CleanerImpl() {
queue = new ReferenceQueue<>();
- phantomCleanableList = new PhantomCleanableRef();
- weakCleanableList = new WeakCleanableRef();
- softCleanableList = new SoftCleanableRef();
+ phantomCleanableList = new PhantomCleanableImpl();
}
/**
* Starts the Cleaner implementation.
* Ensure this is the CleanerImpl for the Cleaner.
@@ -100,13 +97,13 @@
*/
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);
+ // 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();
}
@@ -133,13 +130,11 @@
public void run() {
Thread t = Thread.currentThread();
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();
}
try {
@@ -155,89 +150,112 @@
}
}
}
/**
- * Perform cleaning on an unreachable PhantomReference.
+ * Perform cleaning on an unreachable PhantomCleanable's referent.
+ */
+ public static final class PhantomCleanableImpl extends PhantomCleanable<Object> {
+
+ /**
+ * The list of PhantomCleanableImpl; synchronizes insert and remove.
+ */
+ private final PhantomCleanableImpl list;
+
+ /**
+ * The cleanup action.
*/
- public static final class PhantomCleanableRef extends PhantomCleanable<Object> {
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<Object> {
- 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() {
+ public final void clean() {
+ if (remove()) {
+ super.clear();
+ if (action != null) {
action.run();
}
+ }
+ }
/**
* Prevent access to referent even when it is still alive.
*
* @throws UnsupportedOperationException always
@@ -254,62 +272,34 @@
*/
@Override
public void clear() {
throw new UnsupportedOperationException("clear");
}
- }
-
- /**
- * Perform cleaning on an unreachable SoftReference.
- */
- public static final class SoftCleanableRef extends SoftCleanable<Object> {
- 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");
}
-
}
/**
* A ThreadFactory for InnocuousThreads.
* The factory is a singleton.
@@ -333,20 +323,6 @@
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 >