1/* 2 * Written by Doug Lea with assistance from members of JCP JSR-166 3 * Expert Group and released to the public domain, as explained at 4 * http://creativecommons.org/publicdomain/zero/1.0/ 5 */ 6 7package java.util.concurrent.atomic; 8import dalvik.system.VMStack; // android-added 9import sun.misc.Unsafe; 10import java.lang.reflect.Field; 11import java.lang.reflect.Modifier; 12 13/** 14 * A reflection-based utility that enables atomic updates to 15 * designated {@code volatile} reference fields of designated 16 * classes. This class is designed for use in atomic data structures 17 * in which several reference fields of the same node are 18 * independently subject to atomic updates. For example, a tree node 19 * might be declared as 20 * 21 * <pre> {@code 22 * class Node { 23 * private volatile Node left, right; 24 * 25 * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = 26 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); 27 * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = 28 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); 29 * 30 * Node getLeft() { return left; } 31 * boolean compareAndSetLeft(Node expect, Node update) { 32 * return leftUpdater.compareAndSet(this, expect, update); 33 * } 34 * // ... and so on 35 * }}</pre> 36 * 37 * <p>Note that the guarantees of the {@code compareAndSet} 38 * method in this class are weaker than in other atomic classes. 39 * Because this class cannot ensure that all uses of the field 40 * are appropriate for purposes of atomic access, it can 41 * guarantee atomicity only with respect to other invocations of 42 * {@code compareAndSet} and {@code set} on the same updater. 43 * 44 * @since 1.5 45 * @author Doug Lea 46 * @param <T> The type of the object holding the updatable field 47 * @param <V> The type of the field 48 */ 49public abstract class AtomicReferenceFieldUpdater<T,V> { 50 51 /** 52 * Creates and returns an updater for objects with the given field. 53 * The Class arguments are needed to check that reflective types and 54 * generic types match. 55 * 56 * @param tclass the class of the objects holding the field 57 * @param vclass the class of the field 58 * @param fieldName the name of the field to be updated 59 * @return the updater 60 * @throws IllegalArgumentException if the field is not a volatile reference type 61 * @throws RuntimeException with a nested reflection-based 62 * exception if the class does not hold field or is the wrong type, 63 * or the field is inaccessible to the caller according to Java language 64 * access control 65 */ 66 public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) { 67 return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass, 68 vclass, 69 fieldName); 70 } 71 72 /** 73 * Protected do-nothing constructor for use by subclasses. 74 */ 75 protected AtomicReferenceFieldUpdater() { 76 } 77 78 /** 79 * Atomically sets the field of the given object managed by this updater 80 * to the given updated value if the current value {@code ==} the 81 * expected value. This method is guaranteed to be atomic with respect to 82 * other calls to {@code compareAndSet} and {@code set}, but not 83 * necessarily with respect to other changes in the field. 84 * 85 * @param obj An object whose field to conditionally set 86 * @param expect the expected value 87 * @param update the new value 88 * @return true if successful 89 */ 90 public abstract boolean compareAndSet(T obj, V expect, V update); 91 92 /** 93 * Atomically sets the field of the given object managed by this updater 94 * to the given updated value if the current value {@code ==} the 95 * expected value. This method is guaranteed to be atomic with respect to 96 * other calls to {@code compareAndSet} and {@code set}, but not 97 * necessarily with respect to other changes in the field. 98 * 99 * <p><a href="package-summary.html#weakCompareAndSet">May fail 100 * spuriously and does not provide ordering guarantees</a>, so is 101 * only rarely an appropriate alternative to {@code compareAndSet}. 102 * 103 * @param obj An object whose field to conditionally set 104 * @param expect the expected value 105 * @param update the new value 106 * @return true if successful 107 */ 108 public abstract boolean weakCompareAndSet(T obj, V expect, V update); 109 110 /** 111 * Sets the field of the given object managed by this updater to the 112 * given updated value. This operation is guaranteed to act as a volatile 113 * store with respect to subsequent invocations of {@code compareAndSet}. 114 * 115 * @param obj An object whose field to set 116 * @param newValue the new value 117 */ 118 public abstract void set(T obj, V newValue); 119 120 /** 121 * Eventually sets the field of the given object managed by this 122 * updater to the given updated value. 123 * 124 * @param obj An object whose field to set 125 * @param newValue the new value 126 * @since 1.6 127 */ 128 public abstract void lazySet(T obj, V newValue); 129 130 /** 131 * Gets the current value held in the field of the given object managed 132 * by this updater. 133 * 134 * @param obj An object whose field to get 135 * @return the current value 136 */ 137 public abstract V get(T obj); 138 139 /** 140 * Atomically sets the field of the given object managed by this updater 141 * to the given value and returns the old value. 142 * 143 * @param obj An object whose field to get and set 144 * @param newValue the new value 145 * @return the previous value 146 */ 147 public V getAndSet(T obj, V newValue) { 148 for (;;) { 149 V current = get(obj); 150 if (compareAndSet(obj, current, newValue)) 151 return current; 152 } 153 } 154 155 private static final class AtomicReferenceFieldUpdaterImpl<T,V> 156 extends AtomicReferenceFieldUpdater<T,V> { 157 private static final Unsafe unsafe = Unsafe.getUnsafe(); 158 private final long offset; 159 private final Class<T> tclass; 160 private final Class<V> vclass; 161 private final Class<?> cclass; 162 163 /* 164 * Internal type checks within all update methods contain 165 * internal inlined optimizations checking for the common 166 * cases where the class is final (in which case a simple 167 * getClass comparison suffices) or is of type Object (in 168 * which case no check is needed because all objects are 169 * instances of Object). The Object case is handled simply by 170 * setting vclass to null in constructor. The targetCheck and 171 * updateCheck methods are invoked when these faster 172 * screenings fail. 173 */ 174 175 AtomicReferenceFieldUpdaterImpl(final Class<T> tclass, 176 Class<V> vclass, 177 final String fieldName) { 178 final Field field; 179 final Class<?> fieldClass; 180 final Class<?> caller; 181 final int modifiers; 182 try { 183 field = tclass.getDeclaredField(fieldName); // android-changed 184 caller = VMStack.getStackClass2(); // android-changed 185 modifiers = field.getModifiers(); 186 // BEGIN android-removed 187 // sun.reflect.misc.ReflectUtil.ensureMemberAccess( 188 // caller, tclass, null, modifiers); 189 // ClassLoader cl = tclass.getClassLoader(); 190 // ClassLoader ccl = caller.getClassLoader(); 191 // if ((ccl != null) && (ccl != cl) && 192 // ((cl == null) || !isAncestor(cl, ccl))) { 193 // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 194 // } 195 // END android-removed 196 fieldClass = field.getType(); 197 // BEGIN android-removed 198 // } catch (PrivilegedActionException pae) { 199 // throw new RuntimeException(pae.getException()); 200 // END android-removed 201 } catch (Exception ex) { 202 throw new RuntimeException(ex); 203 } 204 205 if (vclass != fieldClass) 206 throw new ClassCastException(); 207 208 if (!Modifier.isVolatile(modifiers)) 209 throw new IllegalArgumentException("Must be volatile type"); 210 211 this.cclass = (Modifier.isProtected(modifiers) && 212 caller != tclass) ? caller : null; 213 this.tclass = tclass; 214 if (vclass == Object.class) 215 this.vclass = null; 216 else 217 this.vclass = vclass; 218 offset = unsafe.objectFieldOffset(field); 219 } 220 221 // BEGIN android-removed 222 // /** 223 // * Returns true if the second classloader can be found in the first 224 // * classloader's delegation chain. 225 // * Equivalent to the inaccessible: first.isAncestor(second). 226 // */ 227 // 228 // private static boolean isAncestor(ClassLoader first, ClassLoader second) { 229 // ClassLoader acl = first; 230 // do { 231 // acl = acl.getParent(); 232 // if (second == acl) { 233 // return true; 234 // } 235 // } while (acl != null); 236 // return false; 237 // } 238 // END android-removed 239 240 void targetCheck(T obj) { 241 if (!tclass.isInstance(obj)) 242 throw new ClassCastException(); 243 if (cclass != null) 244 ensureProtectedAccess(obj); 245 } 246 247 void updateCheck(T obj, V update) { 248 if (!tclass.isInstance(obj) || 249 (update != null && vclass != null && !vclass.isInstance(update))) 250 throw new ClassCastException(); 251 if (cclass != null) 252 ensureProtectedAccess(obj); 253 } 254 255 public boolean compareAndSet(T obj, V expect, V update) { 256 if (obj == null || obj.getClass() != tclass || cclass != null || 257 (update != null && vclass != null && 258 vclass != update.getClass())) 259 updateCheck(obj, update); 260 return unsafe.compareAndSwapObject(obj, offset, expect, update); 261 } 262 263 public boolean weakCompareAndSet(T obj, V expect, V update) { 264 // same implementation as strong form for now 265 if (obj == null || obj.getClass() != tclass || cclass != null || 266 (update != null && vclass != null && 267 vclass != update.getClass())) 268 updateCheck(obj, update); 269 return unsafe.compareAndSwapObject(obj, offset, expect, update); 270 } 271 272 public void set(T obj, V newValue) { 273 if (obj == null || obj.getClass() != tclass || cclass != null || 274 (newValue != null && vclass != null && 275 vclass != newValue.getClass())) 276 updateCheck(obj, newValue); 277 unsafe.putObjectVolatile(obj, offset, newValue); 278 } 279 280 public void lazySet(T obj, V newValue) { 281 if (obj == null || obj.getClass() != tclass || cclass != null || 282 (newValue != null && vclass != null && 283 vclass != newValue.getClass())) 284 updateCheck(obj, newValue); 285 unsafe.putOrderedObject(obj, offset, newValue); 286 } 287 288 @SuppressWarnings("unchecked") 289 public V get(T obj) { 290 if (obj == null || obj.getClass() != tclass || cclass != null) 291 targetCheck(obj); 292 return (V)unsafe.getObjectVolatile(obj, offset); 293 } 294 295 private void ensureProtectedAccess(T obj) { 296 if (cclass.isInstance(obj)) { 297 return; 298 } 299 throw new RuntimeException( 300 new IllegalAccessException("Class " + 301 cclass.getName() + 302 " can not access a protected member of class " + 303 tclass.getName() + 304 " using an instance of " + 305 obj.getClass().getName() 306 ) 307 ); 308 } 309 } 310} 311