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 }