1 package java.lang.ref;
   2 
   3 import java.util.Objects;
   4 
   5 /**
   6  * A {@link PhantomReference} based {@link Cleaner}.
   7  * <p>
   8  * PhantomCleaner(s) are a lightweight and more robust alternative to finalization.
   9  * They are lightweight because they are not created by the VM and thus do not
  10  * require a JNI upcall to be created. They are more robust because they are
  11  * phantom references, the weakest type of reference object, thereby avoiding the
  12  * nasty ordering problems inherent to finalization.
  13  * <p>
  14  * Some time after the GC detects that PhantomCleaner's referent has
  15  * become phantom-reachable, one of the finalizing thread(s) will
  16  * {@link #clean() invoke} the cleaner.
  17  * PhantomCleaner(s) may also be {@link #clean() invoked} directly. The 1st
  18  * invocation will {@link #clear()} the PhantomCleaner and invoke the
  19  * {@link #doClean() clean-up action}. Subsequent invocations are ignored.
  20  *
  21  * @since 1.9
  22  */
  23 public abstract class PhantomCleaner extends PhantomReference<Object> implements Cleaner {
  24 
  25     /**
  26      * Creates and returns a PhantomCleaner implementation that takes a
  27      * {@code Runnable thunk} to be run as a clean-up action.
  28      * Some time after the {@code referent} becomes phantom-reachable, one of
  29      * the finalizing threads runs the {@code thunk}.
  30      *
  31      * @param referent the referent object to be tracked
  32      * @param thunk    The cleanup code to be run when the cleaner is invoked.  The
  33      *                 cleanup code is run from one of the finalizing thread(s)
  34      *                 that are also used to run other cleaners and finalization or
  35      *                 from user code that invokes the cleaner directly.
  36      * @return The new PhantomCleaner
  37      * @throws NullPointerException if {@code referent} or {@code thunk} is null.
  38      */
  39     public static PhantomCleaner create(Object referent, Runnable thunk) {
  40         Objects.requireNonNull(thunk);
  41         return new PhantomCleaner(referent) {
  42             @Override
  43             protected void doClean() {
  44                 thunk.run();
  45             }
  46         };
  47     }
  48 
  49     /**
  50      * A constructor taking a referent to track.
  51      *
  52      * @param referent the referent to track
  53      * @throws NullPointerException if {@code referent} is null
  54      */
  55     public PhantomCleaner(Object referent) {
  56         super(Objects.requireNonNull(referent), null);
  57         link();
  58     }
  59 
  60     /**
  61      * Invoked at most once after the referent of this
  62      * {@code PhantomCleaner} is found phantom-reachable or when the user
  63      * explicitly invokes {@link #clean()}. Subclasses should implement this
  64      * method and place clean-up actions into it.
  65      */
  66     protected abstract void doClean();
  67 
  68     /**
  69      * Runs this PhantomCleaner, if it has not been run before. This method may be
  70      * invoked by one of the finalizing thread(s) or manually by a client
  71      * thread. Only the 1st invocation will {@link #clear()} this PhantomCleaner
  72      * and invoke {@link #doClean() cleanup-code}. Any unchecked
  73      * exception thrown from the {@link #doClean() cleanup-code} will be propagated.
  74      * When such exception happens as a result of running this method automatically
  75      * by one of the finalizing thread(s), it is ignored.
  76      */
  77     @Override
  78     public final void clean() {
  79         if (delete()) {
  80             super.clear();
  81             unlink();
  82             doClean();
  83         }
  84     }
  85 
  86     @Override
  87     public final void clear() {
  88         if (delete()) {
  89             super.clear();
  90             unlink();
  91         }
  92     }
  93 
  94     // Methods and state that enable PhantomCleaner to be an element of DLList
  95 
  96     @SuppressWarnings("unused") // assigned through Unsafe
  97     private volatile Reference<?> prevDll, nextDll;
  98     @SuppressWarnings("unused") // assigned through Unsafe
  99     private volatile int deletedDll;
 100 
 101     private boolean delete() {
 102         return deletedDll == 0 && UNSAFE.compareAndSwapInt(this, DELETED_DLL, 0, 1);
 103     }
 104 
 105     boolean isDeletedDll() {
 106         return deletedDll == 1;
 107     }
 108 
 109     Reference<?> getPrevDll() {
 110         return prevDll;
 111     }
 112 
 113     void lazySetPrevDll(Reference<?> val) {
 114         UNSAFE.putOrderedObject(this, PREV_DLL, val);
 115     }
 116 
 117     boolean casPrevDll(Reference<?> cmp, Reference<?> val) {
 118         return UNSAFE.compareAndSwapObject(this, PREV_DLL, cmp, val);
 119     }
 120 
 121     Reference<?> getNextDll() {
 122         return nextDll;
 123     }
 124 
 125     void lazySetNextDll(Reference<?> val) {
 126         UNSAFE.putOrderedObject(this, NEXT_DLL, val);
 127     }
 128 
 129     boolean casNextDll(Reference<?> cmp, Reference<?> val) {
 130         return UNSAFE.compareAndSwapObject(this, NEXT_DLL, cmp, val);
 131     }
 132 
 133     // Unsafe machinery
 134 
 135     private static final sun.misc.Unsafe UNSAFE;
 136     private static final long PREV_DLL;
 137     private static final long NEXT_DLL;
 138     private static final long DELETED_DLL;
 139 
 140     static {
 141         try {
 142             UNSAFE = sun.misc.Unsafe.getUnsafe();
 143             Class<PhantomCleaner> pcc = PhantomCleaner.class;
 144             PREV_DLL = UNSAFE.objectFieldOffset(pcc.getDeclaredField("prevDll"));
 145             NEXT_DLL = UNSAFE.objectFieldOffset(pcc.getDeclaredField("nextDll"));
 146             DELETED_DLL = UNSAFE.objectFieldOffset(pcc.getDeclaredField("deletedDll"));
 147         } catch (Exception e) {
 148             throw new Error(e);
 149         }
 150     }
 151 }