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