--- /dev/null 2015-09-02 12:15:01.309625027 +0200 +++ new/src/java.base/share/classes/java/lang/ref/WeakCleanableReference.java 2015-10-02 13:38:12.634441321 +0200 @@ -0,0 +1,96 @@ +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(); + } +}