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