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