2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/licenses/publicdomain
7 package java.util.concurrent.atomic;
8 import sun.misc.Unsafe;
9 import java.lang.reflect.*;
12 * A reflection-based utility that enables atomic updates to
13 * designated <tt>volatile int</tt> fields of designated classes.
14 * This class is designed for use in atomic data structures in which
15 * several fields of the same node are independently subject to atomic
18 * <p>Note that the guarantees of the {@code compareAndSet}
19 * method in this class are weaker than in other atomic classes.
20 * Because this class cannot ensure that all uses of the field
21 * are appropriate for purposes of atomic access, it can
22 * guarantee atomicity only with respect to other invocations of
23 * {@code compareAndSet} and {@code set} on the same updater.
27 * @param <T> The type of the object holding the updatable field
29 public abstract class AtomicIntegerFieldUpdater<T> {
31 * Creates and returns an updater for objects with the given field.
32 * The Class argument is needed to check that reflective types and
33 * generic types match.
35 * @param tclass the class of the objects holding the field
36 * @param fieldName the name of the field to be updated
38 * @throws IllegalArgumentException if the field is not a
39 * volatile integer type
40 * @throws RuntimeException with a nested reflection-based
41 * exception if the class does not hold field or is the wrong type
43 public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
44 return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
48 * Protected do-nothing constructor for use by subclasses.
50 protected AtomicIntegerFieldUpdater() {
54 * Atomically sets the field of the given object managed by this updater
55 * to the given updated value if the current value <tt>==</tt> the
56 * expected value. This method is guaranteed to be atomic with respect to
57 * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not
58 * necessarily with respect to other changes in the field.
60 * @param obj An object whose field to conditionally set
61 * @param expect the expected value
62 * @param update the new value
63 * @return true if successful
64 * @throws ClassCastException if <tt>obj</tt> is not an instance
65 * of the class possessing the field established in the constructor
67 public abstract boolean compareAndSet(T obj, int expect, int update);
70 * Atomically sets the field of the given object managed by this updater
71 * to the given updated value if the current value <tt>==</tt> the
72 * expected value. This method is guaranteed to be atomic with respect to
73 * other calls to <tt>compareAndSet</tt> and <tt>set</tt>, but not
74 * necessarily with respect to other changes in the field.
75 * May fail spuriously and does not provide ordering guarantees,
76 * so is only rarely an appropriate alternative to <tt>compareAndSet</tt>.
78 * @param obj An object whose field to conditionally set
79 * @param expect the expected value
80 * @param update the new value
81 * @return true if successful
82 * @throws ClassCastException if <tt>obj</tt> is not an instance
83 * of the class possessing the field established in the constructor
85 public abstract boolean weakCompareAndSet(T obj, int expect, int update);
88 * Sets the field of the given object managed by this updater to the
89 * given updated value. This operation is guaranteed to act as a volatile
90 * store with respect to subsequent invocations of
91 * <tt>compareAndSet</tt>.
93 * @param obj An object whose field to set
94 * @param newValue the new value
96 public abstract void set(T obj, int newValue);
99 * Eventually sets the field of the given object managed by this
100 * updater to the given updated value.
102 * @param obj An object whose field to set
103 * @param newValue the new value
106 public abstract void lazySet(T obj, int newValue);
110 * Gets the current value held in the field of the given object managed
113 * @param obj An object whose field to get
114 * @return the current value
116 public abstract int get(T obj);
119 * Atomically sets the field of the given object managed by this updater
120 * to the given value and returns the old value.
122 * @param obj An object whose field to get and set
123 * @param newValue the new value
124 * @return the previous value
126 public int getAndSet(T obj, int newValue) {
128 int current = get(obj);
129 if (compareAndSet(obj, current, newValue))
135 * Atomically increments by one the current value of the field of the
136 * given object managed by this updater.
138 * @param obj An object whose field to get and set
139 * @return the previous value
141 public int getAndIncrement(T obj) {
143 int current = get(obj);
144 int next = current + 1;
145 if (compareAndSet(obj, current, next))
151 * Atomically decrements by one the current value of the field of the
152 * given object managed by this updater.
154 * @param obj An object whose field to get and set
155 * @return the previous value
157 public int getAndDecrement(T obj) {
159 int current = get(obj);
160 int next = current - 1;
161 if (compareAndSet(obj, current, next))
167 * Atomically adds the given value to the current value of the field of
168 * the given object managed by this updater.
170 * @param obj An object whose field to get and set
171 * @param delta the value to add
172 * @return the previous value
174 public int getAndAdd(T obj, int delta) {
176 int current = get(obj);
177 int next = current + delta;
178 if (compareAndSet(obj, current, next))
184 * Atomically increments by one the current value of the field of the
185 * given object managed by this updater.
187 * @param obj An object whose field to get and set
188 * @return the updated value
190 public int incrementAndGet(T obj) {
192 int current = get(obj);
193 int next = current + 1;
194 if (compareAndSet(obj, current, next))
200 * Atomically decrements by one the current value of the field of the
201 * given object managed by this updater.
203 * @param obj An object whose field to get and set
204 * @return the updated value
206 public int decrementAndGet(T obj) {
208 int current = get(obj);
209 int next = current - 1;
210 if (compareAndSet(obj, current, next))
216 * Atomically adds the given value to the current value of the field of
217 * the given object managed by this updater.
219 * @param obj An object whose field to get and set
220 * @param delta the value to add
221 * @return the updated value
223 public int addAndGet(T obj, int delta) {
225 int current = get(obj);
226 int next = current + delta;
227 if (compareAndSet(obj, current, next))
233 * Standard hotspot implementation using intrinsics
235 private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> {
236 private static final Unsafe unsafe = Unsafe.getUnsafe();
237 private final long offset;
238 private final Class<T> tclass;
239 private final Class cclass;
241 AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) {
246 field = tclass.getDeclaredField(fieldName);
247 caller = sun.reflect.Reflection.getCallerClass(3);
248 modifiers = field.getModifiers();
249 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
250 caller, tclass, null, modifiers);
251 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
252 } catch(Exception ex) {
253 throw new RuntimeException(ex);
256 Class fieldt = field.getType();
257 if (fieldt != int.class)
258 throw new IllegalArgumentException("Must be integer type");
260 if (!Modifier.isVolatile(modifiers))
261 throw new IllegalArgumentException("Must be volatile type");
263 this.cclass = (Modifier.isProtected(modifiers) &&
264 caller != tclass) ? caller : null;
265 this.tclass = tclass;
266 offset = unsafe.objectFieldOffset(field);
269 private void fullCheck(T obj) {
270 if (!tclass.isInstance(obj))
271 throw new ClassCastException();
273 ensureProtectedAccess(obj);
276 public boolean compareAndSet(T obj, int expect, int update) {
277 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
278 return unsafe.compareAndSwapInt(obj, offset, expect, update);
281 public boolean weakCompareAndSet(T obj, int expect, int update) {
282 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
283 return unsafe.compareAndSwapInt(obj, offset, expect, update);
286 public void set(T obj, int newValue) {
287 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
288 unsafe.putIntVolatile(obj, offset, newValue);
291 public void lazySet(T obj, int newValue) {
292 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
293 unsafe.putOrderedInt(obj, offset, newValue);
296 public final int get(T obj) {
297 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
298 return unsafe.getIntVolatile(obj, offset);
301 private void ensureProtectedAccess(T obj) {
302 if (cclass.isInstance(obj)) {
305 throw new RuntimeException(
306 new IllegalAccessException("Class " +
308 " can not access a protected member of class " +
310 " using an instance of " +
311 obj.getClass().getName()