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 }