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 int} fields of designated classes. 47 * This class is designed for use in atomic data structures in which 48 * several fields of the same node are independently subject to atomic 49 * updates. 50 * 51 * <p>Note that the guarantees of the {@code compareAndSet} 52 * method in this class are weaker than in other atomic classes. 53 * Because this class cannot ensure that all uses of the field 54 * are appropriate for purposes of atomic access, it can 55 * guarantee atomicity only with respect to other invocations of 56 * {@code compareAndSet} and {@code set} on the same updater. 57 * 58 * @since 1.5 59 * @author Doug Lea 60 * @param <T> The type of the object holding the updatable field 61 */ 62 public abstract class AtomicIntegerFieldUpdater<T> { 63 /** 64 * Creates and returns an updater for objects with the given field. 65 * The Class argument is needed to check that reflective types and 66 * generic types match. 67 * 68 * @param tclass the class of the objects holding the field 69 * @param fieldName the name of the field to be updated 70 * @return the updater 71 * @throws IllegalArgumentException if the field is not a 72 * volatile integer type 73 * @throws RuntimeException with a nested reflection-based 74 * exception if the class does not hold field or is the wrong type, 75 * or the field is inaccessible to the caller according to Java language 76 * access control 77 */ 78 public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { 79 return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName); 80 } 81 82 /** 83 * Protected do-nothing constructor for use by subclasses. 84 */ 85 protected AtomicIntegerFieldUpdater() { 86 } 87 88 /** 89 * Atomically sets the field of the given object managed by this updater 90 * to the given updated value if the current value {@code ==} the 91 * expected value. This method is guaranteed to be atomic with respect to 92 * other calls to {@code compareAndSet} and {@code set}, but not 93 * necessarily with respect to other changes in the field. 94 * 95 * @param obj An object whose field to conditionally set 96 * @param expect the expected value 97 * @param update the new value 98 * @return true if successful 99 * @throws ClassCastException if {@code obj} is not an instance 100 * of the class possessing the field established in the constructor 101 */ 102 public abstract boolean compareAndSet(T obj, int expect, int update); 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 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a> 112 * and does not provide ordering guarantees, so is only rarely an 113 * appropriate alternative to {@code compareAndSet}. 114 * 115 * @param obj An object whose field to conditionally set 116 * @param expect the expected value 117 * @param update the new value 118 * @return true if successful 119 * @throws ClassCastException if {@code obj} is not an instance 120 * of the class possessing the field established in the constructor 121 */ 122 public abstract boolean weakCompareAndSet(T obj, int expect, int update); 123 124 /** 125 * Sets the field of the given object managed by this updater to the 126 * given updated value. This operation is guaranteed to act as a volatile 127 * store with respect to subsequent invocations of {@code compareAndSet}. 128 * 129 * @param obj An object whose field to set 130 * @param newValue the new value 131 */ 132 public abstract void set(T obj, int newValue); 133 134 /** 135 * Eventually sets the field of the given object managed by this 136 * updater to the given updated value. 137 * 138 * @param obj An object whose field to set 139 * @param newValue the new value 140 * @since 1.6 141 */ 142 public abstract void lazySet(T obj, int newValue); 143 144 /** 145 * Gets the current value held in the field of the given object managed 146 * by this updater. 147 * 148 * @param obj An object whose field to get 149 * @return the current value 150 */ 151 public abstract int get(T obj); 152 153 /** 154 * Atomically sets the field of the given object managed by this updater 155 * to the given value and returns the old value. 156 * 157 * @param obj An object whose field to get and set 158 * @param newValue the new value 159 * @return the previous value 160 */ 161 public int getAndSet(T obj, int newValue) { 162 for (;;) { 163 int current = get(obj); 164 if (compareAndSet(obj, current, newValue)) 165 return current; 166 } 167 } 168 169 /** 170 * Atomically increments by one the current value of the field of the 171 * given object managed by this updater. 172 * 173 * @param obj An object whose field to get and set 174 * @return the previous value 175 */ 176 public int getAndIncrement(T obj) { 177 for (;;) { 178 int current = get(obj); 179 int next = current + 1; 180 if (compareAndSet(obj, current, next)) 181 return current; 182 } 183 } 184 185 /** 186 * Atomically decrements by one the current value of the field of the 187 * given object managed by this updater. 188 * 189 * @param obj An object whose field to get and set 190 * @return the previous value 191 */ 192 public int getAndDecrement(T obj) { 193 for (;;) { 194 int current = get(obj); 195 int next = current - 1; 196 if (compareAndSet(obj, current, next)) 197 return current; 198 } 199 } 200 201 /** 202 * Atomically adds the given value to the current value of the field of 203 * the given object managed by this updater. 204 * 205 * @param obj An object whose field to get and set 206 * @param delta the value to add 207 * @return the previous value 208 */ 209 public int getAndAdd(T obj, int delta) { 210 for (;;) { 211 int current = get(obj); 212 int next = current + delta; 213 if (compareAndSet(obj, current, next)) 214 return current; 215 } 216 } 217 218 /** 219 * Atomically increments by one the current value of the field of the 220 * given object managed by this updater. 221 * 222 * @param obj An object whose field to get and set 223 * @return the updated value 224 */ 225 public int incrementAndGet(T obj) { 226 for (;;) { 227 int current = get(obj); 228 int next = current + 1; 229 if (compareAndSet(obj, current, next)) 230 return next; 231 } 232 } 233 234 /** 235 * Atomically decrements by one the current value of the field of the 236 * given object managed by this updater. 237 * 238 * @param obj An object whose field to get and set 239 * @return the updated value 240 */ 241 public int decrementAndGet(T obj) { 242 for (;;) { 243 int current = get(obj); 244 int next = current - 1; 245 if (compareAndSet(obj, current, next)) 246 return next; 247 } 248 } 249 250 /** 251 * Atomically adds the given value to the current value of the field of 252 * the given object managed by this updater. 253 * 254 * @param obj An object whose field to get and set 255 * @param delta the value to add 256 * @return the updated value 257 */ 258 public int addAndGet(T obj, int delta) { 259 for (;;) { 260 int current = get(obj); 261 int next = current + delta; 262 if (compareAndSet(obj, current, next)) 263 return next; 264 } 265 } 266 267 /** 268 * Standard hotspot implementation using intrinsics 269 */ 270 private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> { 271 private static final Unsafe unsafe = Unsafe.getUnsafe(); 272 private final long offset; 273 private final Class<T> tclass; 274 private final Class<?> cclass; 275 276 AtomicIntegerFieldUpdaterImpl(final Class<T> tclass, final String fieldName) { 277 final Field field; 278 final Class<?> caller; 279 final int modifiers; 280 try { 281 field = AccessController.doPrivileged( 282 new PrivilegedExceptionAction<Field>() { 283 public Field run() throws NoSuchFieldException { 284 return tclass.getDeclaredField(fieldName); 285 } 286 }); 287 caller = sun.reflect.Reflection.getCallerClass(3); 288 modifiers = field.getModifiers(); 289 sun.reflect.misc.ReflectUtil.ensureMemberAccess( 290 caller, tclass, null, modifiers); 291 ClassLoader cl = tclass.getClassLoader(); 292 ClassLoader ccl = caller.getClassLoader(); 293 if ((ccl != null) && (ccl != cl) && 294 ((cl == null) || !isAncestor(cl, ccl))) { 295 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 296 } 297 } catch (PrivilegedActionException pae) { 298 throw new RuntimeException(pae.getException()); 299 } catch (Exception ex) { 300 throw new RuntimeException(ex); 301 } 302 303 Class<?> fieldt = field.getType(); 304 if (fieldt != int.class) 305 throw new IllegalArgumentException("Must be integer type"); 306 307 if (!Modifier.isVolatile(modifiers)) 308 throw new IllegalArgumentException("Must be volatile type"); 309 310 this.cclass = (Modifier.isProtected(modifiers) && 311 caller != tclass) ? caller : null; 312 this.tclass = tclass; 313 offset = unsafe.objectFieldOffset(field); 314 } 315 316 /** 317 * Returns true if the second classloader can be found in the first 318 * classloader's delegation chain. 319 * Equivalent to the inaccessible: first.isAncestor(second). 320 */ 321 private static boolean isAncestor(ClassLoader first, ClassLoader second) { 322 ClassLoader acl = first; 323 do { 324 acl = acl.getParent(); 325 if (second == acl) { 326 return true; 327 } 328 } while (acl != null); 329 return false; 330 } 331 332 private void fullCheck(T obj) { 333 if (!tclass.isInstance(obj)) 334 throw new ClassCastException(); 335 if (cclass != null) 336 ensureProtectedAccess(obj); 337 } 338 339 public boolean compareAndSet(T obj, int expect, int update) { 340 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 341 return unsafe.compareAndSwapInt(obj, offset, expect, update); 342 } 343 344 public boolean weakCompareAndSet(T obj, int expect, int update) { 345 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 346 return unsafe.compareAndSwapInt(obj, offset, expect, update); 347 } 348 349 public void set(T obj, int newValue) { 350 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 351 unsafe.putIntVolatile(obj, offset, newValue); 352 } 353 354 public void lazySet(T obj, int newValue) { 355 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 356 unsafe.putOrderedInt(obj, offset, newValue); 357 } 358 359 public final int get(T obj) { 360 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 361 return unsafe.getIntVolatile(obj, offset); 362 } 363 364 private void ensureProtectedAccess(T obj) { 365 if (cclass.isInstance(obj)) { 366 return; 367 } 368 throw new RuntimeException( 369 new IllegalAccessException("Class " + 370 cclass.getName() + 371 " can not access a protected member of class " + 372 tclass.getName() + 373 " using an instance of " + 374 obj.getClass().getName() 375 ) 376 ); 377 } 378 } 379 }