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