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 long} 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 AtomicLongFieldUpdater<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 long 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> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { 73 if (AtomicLong.VM_SUPPORTS_LONG_CAS) 74 return new CASUpdater<U>(tclass, fieldName); 75 else 76 return new LockedUpdater<U>(tclass, fieldName); 77 } 78 79 /** 80 * Protected do-nothing constructor for use by subclasses. 81 */ 82 protected AtomicLongFieldUpdater() { 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, long expect, long 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, long expect, long 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, long 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, long newValue); 140 141 /** 142 * Gets the current value held in the field of the given object managed 143 * by this updater. 144 * 145 * @param obj An object whose field to get 146 * @return the current value 147 */ 148 public abstract long get(T obj); 149 150 /** 151 * Atomically sets the field of the given object managed by this updater 152 * to the given value and returns the old value. 153 * 154 * @param obj An object whose field to get and set 155 * @param newValue the new value 156 * @return the previous value 157 */ 158 public long getAndSet(T obj, long newValue) { 159 for (;;) { 160 long current = get(obj); 161 if (compareAndSet(obj, current, newValue)) 162 return current; 163 } 164 } 165 166 /** 167 * Atomically increments by one the current value of the field of the 168 * given object managed by this updater. 169 * 170 * @param obj An object whose field to get and set 171 * @return the previous value 172 */ 173 public long getAndIncrement(T obj) { 174 for (;;) { 175 long current = get(obj); 176 long next = current + 1; 177 if (compareAndSet(obj, current, next)) 178 return current; 179 } 180 } 181 182 /** 183 * Atomically decrements by one the current value of the field of the 184 * given object managed by this updater. 185 * 186 * @param obj An object whose field to get and set 187 * @return the previous value 188 */ 189 public long getAndDecrement(T obj) { 190 for (;;) { 191 long current = get(obj); 192 long next = current - 1; 193 if (compareAndSet(obj, current, next)) 194 return current; 195 } 196 } 197 198 /** 199 * Atomically adds the given value to the current value of the field of 200 * the given object managed by this updater. 201 * 202 * @param obj An object whose field to get and set 203 * @param delta the value to add 204 * @return the previous value 205 */ 206 public long getAndAdd(T obj, long delta) { 207 for (;;) { 208 long current = get(obj); 209 long next = current + delta; 210 if (compareAndSet(obj, current, next)) 211 return current; 212 } 213 } 214 215 /** 216 * Atomically increments by one the current value of the field of the 217 * given object managed by this updater. 218 * 219 * @param obj An object whose field to get and set 220 * @return the updated value 221 */ 222 public long incrementAndGet(T obj) { 223 for (;;) { 224 long current = get(obj); 225 long next = current + 1; 226 if (compareAndSet(obj, current, next)) 227 return next; 228 } 229 } 230 231 /** 232 * Atomically decrements by one the current value of the field of the 233 * given object managed by this updater. 234 * 235 * @param obj An object whose field to get and set 236 * @return the updated value 237 */ 238 public long decrementAndGet(T obj) { 239 for (;;) { 240 long current = get(obj); 241 long next = current - 1; 242 if (compareAndSet(obj, current, next)) 243 return next; 244 } 245 } 246 247 /** 248 * Atomically adds the given value to the current value of the field of 249 * the given object managed by this updater. 250 * 251 * @param obj An object whose field to get and set 252 * @param delta the value to add 253 * @return the updated value 254 */ 255 public long addAndGet(T obj, long delta) { 256 for (;;) { 257 long current = get(obj); 258 long next = current + delta; 259 if (compareAndSet(obj, current, next)) 260 return next; 261 } 262 } 263 264 private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> { 265 private static final Unsafe unsafe = Unsafe.getUnsafe(); 266 private final long offset; 267 private final Class<T> tclass; 268 private final Class cclass; 269 270 CASUpdater(Class<T> tclass, String fieldName) { 271 Field field = null; 272 Class caller = null; 273 int modifiers = 0; 274 try { 275 field = tclass.getDeclaredField(fieldName); 276 caller = sun.reflect.Reflection.getCallerClass(3); 277 modifiers = field.getModifiers(); 278 sun.reflect.misc.ReflectUtil.ensureMemberAccess( 279 caller, tclass, null, modifiers); 280 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 281 } catch (Exception ex) { 282 throw new RuntimeException(ex); 283 } 284 285 Class fieldt = field.getType(); 286 if (fieldt != long.class) 287 throw new IllegalArgumentException("Must be long type"); 288 289 if (!Modifier.isVolatile(modifiers)) 290 throw new IllegalArgumentException("Must be volatile type"); 291 292 this.cclass = (Modifier.isProtected(modifiers) && 293 caller != tclass) ? caller : null; 294 this.tclass = tclass; 295 offset = unsafe.objectFieldOffset(field); 296 } 297 298 private void fullCheck(T obj) { 299 if (!tclass.isInstance(obj)) 300 throw new ClassCastException(); 301 if (cclass != null) 302 ensureProtectedAccess(obj); 303 } 304 305 public boolean compareAndSet(T obj, long expect, long update) { 306 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 307 return unsafe.compareAndSwapLong(obj, offset, expect, update); 308 } 309 310 public boolean weakCompareAndSet(T obj, long expect, long update) { 311 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 312 return unsafe.compareAndSwapLong(obj, offset, expect, update); 313 } 314 315 public void set(T obj, long newValue) { 316 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 317 unsafe.putLongVolatile(obj, offset, newValue); 318 } 319 320 public void lazySet(T obj, long newValue) { 321 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 322 unsafe.putOrderedLong(obj, offset, newValue); 323 } 324 325 public long get(T obj) { 326 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 327 return unsafe.getLongVolatile(obj, offset); 328 } 329 330 private void ensureProtectedAccess(T obj) { 331 if (cclass.isInstance(obj)) { 332 return; 333 } 334 throw new RuntimeException( 335 new IllegalAccessException("Class " + 336 cclass.getName() + 337 " can not access a protected member of class " + 338 tclass.getName() + 339 " using an instance of " + 340 obj.getClass().getName() 341 ) 342 ); 343 } 344 } 345 346 347 private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> { 348 private static final Unsafe unsafe = Unsafe.getUnsafe(); 349 private final long offset; 350 private final Class<T> tclass; 351 private final Class cclass; 352 353 LockedUpdater(Class<T> tclass, String fieldName) { 354 Field field = null; 355 Class caller = null; 356 int modifiers = 0; 357 try { 358 field = tclass.getDeclaredField(fieldName); 359 caller = sun.reflect.Reflection.getCallerClass(3); 360 modifiers = field.getModifiers(); 361 sun.reflect.misc.ReflectUtil.ensureMemberAccess( 362 caller, tclass, null, modifiers); 363 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); 364 } catch (Exception ex) { 365 throw new RuntimeException(ex); 366 } 367 368 Class fieldt = field.getType(); 369 if (fieldt != long.class) 370 throw new IllegalArgumentException("Must be long type"); 371 372 if (!Modifier.isVolatile(modifiers)) 373 throw new IllegalArgumentException("Must be volatile type"); 374 375 this.cclass = (Modifier.isProtected(modifiers) && 376 caller != tclass) ? caller : null; 377 this.tclass = tclass; 378 offset = unsafe.objectFieldOffset(field); 379 } 380 381 private void fullCheck(T obj) { 382 if (!tclass.isInstance(obj)) 383 throw new ClassCastException(); 384 if (cclass != null) 385 ensureProtectedAccess(obj); 386 } 387 388 public boolean compareAndSet(T obj, long expect, long update) { 389 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 390 synchronized (this) { 391 long v = unsafe.getLong(obj, offset); 392 if (v != expect) 393 return false; 394 unsafe.putLong(obj, offset, update); 395 return true; 396 } 397 } 398 399 public boolean weakCompareAndSet(T obj, long expect, long update) { 400 return compareAndSet(obj, expect, update); 401 } 402 403 public void set(T obj, long newValue) { 404 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 405 synchronized (this) { 406 unsafe.putLong(obj, offset, newValue); 407 } 408 } 409 410 public void lazySet(T obj, long newValue) { 411 set(obj, newValue); 412 } 413 414 public long get(T obj) { 415 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); 416 synchronized (this) { 417 return unsafe.getLong(obj, offset); 418 } 419 } 420 421 private void ensureProtectedAccess(T obj) { 422 if (cclass.isInstance(obj)) { 423 return; 424 } 425 throw new RuntimeException( 426 new IllegalAccessException("Class " + 427 cclass.getName() + 428 " can not access a protected member of class " + 429 tclass.getName() + 430 " using an instance of " + 431 obj.getClass().getName() 432 ) 433 ); 434 } 435 } 436 }