1 package java.lang.ref; 2 3 import java.util.Objects; 4 5 /** 6 * An abstract {@link PhantomReference} subclass that is registered with a 7 * {@link Cleaner} which employs a thread that invokes {@link #clean()} after 8 * this reference's referent becomes phantom reachable. 9 * Subclasses implement abstract {@link #performCleanup()} method which is called 10 * at most once by the {@code Cleaner}'s thread or by a user thread that invokes 11 * {@link #clean()} explicitly. 12 */ 13 public abstract class PhantomCleanableReference<T> extends PhantomReference<T> 14 implements Cleaner.Cleanable { 15 16 /** 17 * Links to previous and next in a doubly-linked list, 18 * maintained by cleanerImpl. 19 */ 20 Cleaner.Cleanable prev = this, next = this; 21 22 private final Cleaner.CleanerImpl cleanerImpl; 23 24 /** 25 * Constructs new {@code PhantomCleanableReference} with non-null 26 * {@code referent} and {@code cleaner}. The {@code cleaner} 27 * is not retained by this reference - it is just used briefly to 28 * register the constructed reference for {@link Cleaner.Cleanable cleanup}. 29 * 30 * @param referent the referent to track 31 * @param cleaner the {@code Cleaner} to register new reference with 32 */ 33 public PhantomCleanableReference(T referent, Cleaner cleaner) { 34 super(Objects.requireNonNull(referent), cleaner.impl.queue); 35 cleanerImpl = cleaner.impl; 36 cleanerImpl.insert(this); 37 } 38 39 /** 40 * Unregister this Cleanable reference and invoke {@link #performCleanup()}, 41 * ensuring at-most-once semantics. 42 */ 43 @Override 44 public void clean() { 45 if (cleanerImpl.remove(this)) { 46 super.clear(); 47 performCleanup(); 48 } 49 } 50 51 /** 52 * Unregisters this Cleanable reference and clears it. 53 * Due to inherent concurrency, {@link #performCleanup()} may still be invoked. 54 */ 55 @Override 56 public void clear() { 57 if (cleanerImpl.remove(this)) { 58 super.clear(); 59 } 60 } 61 62 /** 63 * This method, implemented by a subclass, contains the cleanup logic. 64 * It is guaranteed to be called at most once. Either by {@link Cleaner} 65 * thread after VM discovers this reference's referent as being phantom 66 * reachable or by a user thread that explicitly calls {@link #clean()} on 67 * this instance.<p> 68 * This method is called after this reference has already been 69 * {@link Reference#clear() cleared}, so it does not have access to a referent. 70 */ 71 protected abstract void performCleanup(); 72 73 /** 74 * This method always throws {@link UnsupportedOperationException}. 75 * Enqueueing details of {@link Cleaner.Cleanable} 76 * references are private implementation detail. 77 * 78 * @return nothing 79 */ 80 @Override 81 public boolean isEnqueued() { 82 throw new UnsupportedOperationException(); 83 } 84 85 /** 86 * This method always throws {@link UnsupportedOperationException}. 87 * Enqueueing details of {@link Cleaner.Cleanable} 88 * references are private implementation detail. 89 * 90 * @return nothing 91 */ 92 @Override 93 public boolean enqueue() { 94 throw new UnsupportedOperationException(); 95 } 96 }