package java.lang.ref; import java.util.Objects; /** * An abstract {@link WeakReference} subclass that is registered with a * {@link Cleaner} which employs a thread that invokes {@link #clean()} after * this reference's referent becomes weakly reachable. * Subclasses implement abstract {@link #performCleanup()} method which is called * at most once by the {@code Cleaner}'s thread or by a user thread that invokes * {@link #clean()} explicitly. */ public abstract class WeakCleanableReference extends WeakReference implements Cleaner.Cleanable { /** * Links to previous and next in a doubly-linked list, * maintained by cleanerImpl. */ Cleaner.Cleanable prev = this, next = this; private final Cleaner.CleanerImpl cleanerImpl; /** * Constructs new {@code WeakCleanableReference} with non-null * {@code referent} and {@code cleaner}. The {@code cleaner} * is not retained by this reference - it is just used briefly to * register the constructed reference for {@link Cleaner.Cleanable cleanup}. * * @param referent the referent to track * @param cleaner the {@code Cleaner} to register new reference with */ public WeakCleanableReference(T referent, Cleaner cleaner) { super(Objects.requireNonNull(referent), cleaner.impl.queue); cleanerImpl = cleaner.impl; cleanerImpl.insert(this); } /** * Unregister this Cleanable reference and invoke {@link #performCleanup()}, * ensuring at-most-once semantics. */ @Override public void clean() { if (cleanerImpl.remove(this)) { super.clear(); performCleanup(); } } /** * Unregisters this Cleanable reference and clears it. * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. */ @Override public void clear() { if (cleanerImpl.remove(this)) { super.clear(); } } /** * This method, implemented by a subclass, contains the cleanup logic. * It is guaranteed to be called at most once. Either by {@link Cleaner} * thread after VM discovers this reference's referent as being weakly * reachable or by a user thread that explicitly calls {@link #clean()} on * this instance.

* This method is called after this reference has already been * {@link Reference#clear() cleared}, so it does not have access to a referent. */ protected abstract void performCleanup(); /** * This method always throws {@link UnsupportedOperationException}. * Enqueueing details of {@link java.lang.ref.Cleaner.Cleanable} * references are private implementation detail. * * @return nothing */ @Override public boolean isEnqueued() { throw new UnsupportedOperationException(); } /** * This method always throws {@link UnsupportedOperationException}. * Enqueueing details of {@link java.lang.ref.Cleaner.Cleanable} * references are private implementation detail. * * @return nothing */ @Override public boolean enqueue() { throw new UnsupportedOperationException(); } }