001: /*
002: * Written by Doug Lea with assistance from members of JCP JSR-166
003: * Expert Group and released to the public domain, as explained at
004: * http://creativecommons.org/licenses/publicdomain
005: */
006:
007: package java.util.concurrent.atomic;
008:
009: import sun.misc.Unsafe;
010: import java.lang.reflect.*;
011:
012: /**
013: * A reflection-based utility that enables atomic updates to
014: * designated <tt>volatile long</tt> fields of designated classes.
015: * This class is designed for use in atomic data structures in which
016: * several fields of the same node are independently subject to atomic
017: * updates.
018: *
019: * <p> Note that the guarantees of the <tt>compareAndSet</tt> method
020: * in this class are weaker than in other atomic classes. Because this
021: * class cannot ensure that all uses of the field are appropriate for
022: * purposes of atomic access, it can guarantee atomicity and volatile
023: * semantics only with respect to other invocations of
024: * <tt>compareAndSet</tt> and <tt>set</tt>.
025: *
026: * @since 1.5
027: * @author Doug Lea
028: * @param <T> The type of the object holding the updatable field
029: */
030: public abstract class AtomicLongFieldUpdater<T> {
031: /**
032: * Creates an updater for objects with the given field. The Class
033: * argument is needed to check that reflective types and generic
034: * types match.
035: * @param tclass the class of the objects holding the field
036: * @param fieldName the name of the field to be updated.
037: * @return the updater
038: * @throws IllegalArgumentException if the field is not a
039: * volatile long type.
040: * @throws RuntimeException with a nested reflection-based
041: * exception if the class does not hold field or is the wrong type.
042: */
043: public static <U> AtomicLongFieldUpdater<U> newUpdater(
044: Class<U> tclass, String fieldName) {
045: if (AtomicLong.VM_SUPPORTS_LONG_CAS)
046: return new CASUpdater<U>(tclass, fieldName);
047: else
048: return new LockedUpdater<U>(tclass, fieldName);
049: }
050:
051: /**
052: * Protected do-nothing constructor for use by subclasses.
053: */
054: protected AtomicLongFieldUpdater() {
055: }
056:
057: /**
058: * Atomically set the value of the field of the given object managed
059: * by this Updater to the given updated value if the current value
060: * <tt>==</tt> the expected value. This method is guaranteed to be
061: * atomic with respect to other calls to <tt>compareAndSet</tt> and
062: * <tt>set</tt>, but not necessarily with respect to other
063: * changes in the field.
064: * @param obj An object whose field to conditionally set
065: * @param expect the expected value
066: * @param update the new value
067: * @return true if successful.
068: * @throws ClassCastException if <tt>obj</tt> is not an instance
069: * of the class possessing the field established in the constructor.
070: */
071:
072: public abstract boolean compareAndSet(T obj, long expect,
073: long update);
074:
075: /**
076: * Atomically set the value of the field of the given object managed
077: * by this Updater to the given updated value if the current value
078: * <tt>==</tt> the expected value. This method is guaranteed to be
079: * atomic with respect to other calls to <tt>compareAndSet</tt> and
080: * <tt>set</tt>, but not necessarily with respect to other
081: * changes in the field, and may fail spuriously.
082: * @param obj An object whose field to conditionally set
083: * @param expect the expected value
084: * @param update the new value
085: * @return true if successful.
086: * @throws ClassCastException if <tt>obj</tt> is not an instance
087: * of the class possessing the field established in the constructor.
088: */
089:
090: public abstract boolean weakCompareAndSet(T obj, long expect,
091: long update);
092:
093: /**
094: * Set the field of the given object managed by this updater. This
095: * operation is guaranteed to act as a volatile store with respect
096: * to subsequent invocations of <tt>compareAndSet</tt>.
097: * @param obj An object whose field to set
098: * @param newValue the new value
099: */
100: public abstract void set(T obj, long newValue);
101:
102: /**
103: * Get the current value held in the field by the given object.
104: * @param obj An object whose field to get
105: * @return the current value
106: */
107: public abstract long get(T obj);
108:
109: /**
110: * Set to the given value and return the old value.
111: *
112: * @param obj An object whose field to get and set
113: * @param newValue the new value
114: * @return the previous value
115: */
116: public long getAndSet(T obj, long newValue) {
117: for (;;) {
118: long current = get(obj);
119: if (compareAndSet(obj, current, newValue))
120: return current;
121: }
122: }
123:
124: /**
125: * Atomically increment by one the current value.
126: * @param obj An object whose field to get and set
127: * @return the previous value;
128: */
129: public long getAndIncrement(T obj) {
130: for (;;) {
131: long current = get(obj);
132: long next = current + 1;
133: if (compareAndSet(obj, current, next))
134: return current;
135: }
136: }
137:
138: /**
139: * Atomically decrement by one the current value.
140: * @param obj An object whose field to get and set
141: * @return the previous value;
142: */
143: public long getAndDecrement(T obj) {
144: for (;;) {
145: long current = get(obj);
146: long next = current - 1;
147: if (compareAndSet(obj, current, next))
148: return current;
149: }
150: }
151:
152: /**
153: * Atomically add the given value to current value.
154: * @param obj An object whose field to get and set
155: * @param delta the value to add
156: * @return the previous value;
157: */
158: public long getAndAdd(T obj, long delta) {
159: for (;;) {
160: long current = get(obj);
161: long next = current + delta;
162: if (compareAndSet(obj, current, next))
163: return current;
164: }
165: }
166:
167: /**
168: * Atomically increment by one the current value.
169: * @param obj An object whose field to get and set
170: * @return the updated value;
171: */
172: public long incrementAndGet(T obj) {
173: for (;;) {
174: long current = get(obj);
175: long next = current + 1;
176: if (compareAndSet(obj, current, next))
177: return next;
178: }
179: }
180:
181: /**
182: * Atomically decrement by one the current value.
183: * @param obj An object whose field to get and set
184: * @return the updated value;
185: */
186: public long decrementAndGet(T obj) {
187: for (;;) {
188: long current = get(obj);
189: long next = current - 1;
190: if (compareAndSet(obj, current, next))
191: return next;
192: }
193: }
194:
195: /**
196: * Atomically add the given value to current value.
197: * @param obj An object whose field to get and set
198: * @param delta the value to add
199: * @return the updated value;
200: */
201: public long addAndGet(T obj, long delta) {
202: for (;;) {
203: long current = get(obj);
204: long next = current + delta;
205: if (compareAndSet(obj, current, next))
206: return next;
207: }
208: }
209:
210: private static class CASUpdater<T> extends
211: AtomicLongFieldUpdater<T> {
212: private static final Unsafe unsafe = Unsafe.getUnsafe();
213: private final long offset;
214: private final Class<T> tclass;
215:
216: CASUpdater(Class<T> tclass, String fieldName) {
217: Field field = null;
218: try {
219: field = tclass.getDeclaredField(fieldName);
220: } catch (Exception ex) {
221: throw new RuntimeException(ex);
222: }
223:
224: Class fieldt = field.getType();
225: if (fieldt != long.class)
226: throw new IllegalArgumentException("Must be long type");
227:
228: if (!Modifier.isVolatile(field.getModifiers()))
229: throw new IllegalArgumentException(
230: "Must be volatile type");
231:
232: this .tclass = tclass;
233: offset = unsafe.objectFieldOffset(field);
234: }
235:
236: public boolean compareAndSet(T obj, long expect, long update) {
237: if (!tclass.isInstance(obj))
238: throw new ClassCastException();
239: return unsafe.compareAndSwapLong(obj, offset, expect,
240: update);
241: }
242:
243: public boolean weakCompareAndSet(T obj, long expect, long update) {
244: if (!tclass.isInstance(obj))
245: throw new ClassCastException();
246: return unsafe.compareAndSwapLong(obj, offset, expect,
247: update);
248: }
249:
250: public void set(T obj, long newValue) {
251: if (!tclass.isInstance(obj))
252: throw new ClassCastException();
253: unsafe.putLongVolatile(obj, offset, newValue);
254: }
255:
256: public long get(T obj) {
257: if (!tclass.isInstance(obj))
258: throw new ClassCastException();
259: return unsafe.getLongVolatile(obj, offset);
260: }
261: }
262:
263: private static class LockedUpdater<T> extends
264: AtomicLongFieldUpdater<T> {
265: private static final Unsafe unsafe = Unsafe.getUnsafe();
266: private final long offset;
267: private final Class<T> tclass;
268:
269: LockedUpdater(Class<T> tclass, String fieldName) {
270: Field field = null;
271: try {
272: field = tclass.getDeclaredField(fieldName);
273: } catch (Exception ex) {
274: throw new RuntimeException(ex);
275: }
276:
277: Class fieldt = field.getType();
278: if (fieldt != long.class)
279: throw new IllegalArgumentException("Must be long type");
280:
281: if (!Modifier.isVolatile(field.getModifiers()))
282: throw new IllegalArgumentException(
283: "Must be volatile type");
284:
285: this .tclass = tclass;
286: offset = unsafe.objectFieldOffset(field);
287: }
288:
289: public boolean compareAndSet(T obj, long expect, long update) {
290: if (!tclass.isInstance(obj))
291: throw new ClassCastException();
292: synchronized (this ) {
293: long v = unsafe.getLong(obj, offset);
294: if (v != expect)
295: return false;
296: unsafe.putLong(obj, offset, update);
297: return true;
298: }
299: }
300:
301: public boolean weakCompareAndSet(T obj, long expect, long update) {
302: return compareAndSet(obj, expect, update);
303: }
304:
305: public void set(T obj, long newValue) {
306: if (!tclass.isInstance(obj))
307: throw new ClassCastException();
308: synchronized (this ) {
309: unsafe.putLong(obj, offset, newValue);
310: }
311: }
312:
313: public long get(T obj) {
314: if (!tclass.isInstance(obj))
315: throw new ClassCastException();
316: synchronized (this) {
317: return unsafe.getLong(obj, offset);
318: }
319: }
320: }
321: }
|