ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk7/java/util/concurrent/atomic/AtomicLongFieldUpdater.java
Revision: 1.3
Committed: Tue Feb 5 19:54:07 2013 UTC (11 years, 4 months ago) by jsr166
Branch: MAIN
Changes since 1.2: +4 -4 lines
Log Message:
javadoc style

File Contents

# User Rev Content
1 dl 1.1 /*
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/publicdomain/zero/1.0/
5     */
6    
7     package java.util.concurrent.atomic;
8     import sun.misc.Unsafe;
9     import java.lang.reflect.Field;
10     import java.lang.reflect.Modifier;
11     import java.security.AccessController;
12     import java.security.PrivilegedExceptionAction;
13     import java.security.PrivilegedActionException;
14    
15     /**
16     * A reflection-based utility that enables atomic updates to
17     * designated {@code volatile long} fields of designated classes.
18     * This class is designed for use in atomic data structures in which
19     * several fields of the same node are independently subject to atomic
20     * updates.
21     *
22     * <p>Note that the guarantees of the {@code compareAndSet}
23     * method in this class are weaker than in other atomic classes.
24     * Because this class cannot ensure that all uses of the field
25     * are appropriate for purposes of atomic access, it can
26     * guarantee atomicity only with respect to other invocations of
27     * {@code compareAndSet} and {@code set} on the same updater.
28     *
29     * @since 1.5
30     * @author Doug Lea
31     * @param <T> The type of the object holding the updatable field
32     */
33     public abstract class AtomicLongFieldUpdater<T> {
34     /**
35     * Creates and returns an updater for objects with the given field.
36     * The Class argument is needed to check that reflective types and
37     * generic types match.
38     *
39     * @param tclass the class of the objects holding the field
40 jsr166 1.3 * @param fieldName the name of the field to be updated
41 dl 1.1 * @return the updater
42     * @throws IllegalArgumentException if the field is not a
43 jsr166 1.3 * volatile long type
44 dl 1.1 * @throws RuntimeException with a nested reflection-based
45     * exception if the class does not hold field or is the wrong type,
46     * or the field is inaccessible to the caller according to Java language
47     * access control
48     */
49     public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
50     if (AtomicLong.VM_SUPPORTS_LONG_CAS)
51     return new CASUpdater<U>(tclass, fieldName);
52     else
53     return new LockedUpdater<U>(tclass, fieldName);
54     }
55    
56     /**
57     * Protected do-nothing constructor for use by subclasses.
58     */
59     protected AtomicLongFieldUpdater() {
60     }
61    
62     /**
63     * Atomically sets the field of the given object managed by this updater
64     * to the given updated value if the current value {@code ==} the
65     * expected value. This method is guaranteed to be atomic with respect to
66     * other calls to {@code compareAndSet} and {@code set}, but not
67     * necessarily with respect to other changes in the field.
68     *
69     * @param obj An object whose field to conditionally set
70     * @param expect the expected value
71     * @param update the new value
72 jsr166 1.2 * @return true if successful
73 dl 1.1 * @throws ClassCastException if {@code obj} is not an instance
74 jsr166 1.3 * of the class possessing the field established in the constructor
75 dl 1.1 */
76     public abstract boolean compareAndSet(T obj, long expect, long update);
77    
78     /**
79     * Atomically sets the field of the given object managed by this updater
80     * to the given updated value if the current value {@code ==} the
81     * expected value. This method is guaranteed to be atomic with respect to
82     * other calls to {@code compareAndSet} and {@code set}, but not
83     * necessarily with respect to other changes in the field.
84     *
85     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
86     * and does not provide ordering guarantees, so is only rarely an
87     * appropriate alternative to {@code compareAndSet}.
88     *
89     * @param obj An object whose field to conditionally set
90     * @param expect the expected value
91     * @param update the new value
92 jsr166 1.2 * @return true if successful
93 dl 1.1 * @throws ClassCastException if {@code obj} is not an instance
94 jsr166 1.3 * of the class possessing the field established in the constructor
95 dl 1.1 */
96     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
97    
98     /**
99     * Sets the field of the given object managed by this updater to the
100     * given updated value. This operation is guaranteed to act as a volatile
101     * store with respect to subsequent invocations of {@code compareAndSet}.
102     *
103     * @param obj An object whose field to set
104     * @param newValue the new value
105     */
106     public abstract void set(T obj, long newValue);
107    
108     /**
109     * Eventually sets the field of the given object managed by this
110     * updater to the given updated value.
111     *
112     * @param obj An object whose field to set
113     * @param newValue the new value
114     * @since 1.6
115     */
116     public abstract void lazySet(T obj, long newValue);
117    
118     /**
119     * Gets the current value held in the field of the given object managed
120     * by this updater.
121     *
122     * @param obj An object whose field to get
123     * @return the current value
124     */
125     public abstract long get(T obj);
126    
127     /**
128     * Atomically sets the field of the given object managed by this updater
129     * to the given value and returns the old value.
130     *
131     * @param obj An object whose field to get and set
132     * @param newValue the new value
133     * @return the previous value
134     */
135     public long getAndSet(T obj, long newValue) {
136     for (;;) {
137     long current = get(obj);
138     if (compareAndSet(obj, current, newValue))
139     return current;
140     }
141     }
142    
143     /**
144     * Atomically increments by one the current value of the field of the
145     * given object managed by this updater.
146     *
147     * @param obj An object whose field to get and set
148     * @return the previous value
149     */
150     public long getAndIncrement(T obj) {
151     for (;;) {
152     long current = get(obj);
153     long next = current + 1;
154     if (compareAndSet(obj, current, next))
155     return current;
156     }
157     }
158    
159     /**
160     * Atomically decrements by one the current value of the field of the
161     * given object managed by this updater.
162     *
163     * @param obj An object whose field to get and set
164     * @return the previous value
165     */
166     public long getAndDecrement(T obj) {
167     for (;;) {
168     long current = get(obj);
169     long next = current - 1;
170     if (compareAndSet(obj, current, next))
171     return current;
172     }
173     }
174    
175     /**
176     * Atomically adds the given value to the current value of the field of
177     * the given object managed by this updater.
178     *
179     * @param obj An object whose field to get and set
180     * @param delta the value to add
181     * @return the previous value
182     */
183     public long getAndAdd(T obj, long delta) {
184     for (;;) {
185     long current = get(obj);
186     long next = current + delta;
187     if (compareAndSet(obj, current, next))
188     return current;
189     }
190     }
191    
192     /**
193     * Atomically increments by one the current value of the field of the
194     * given object managed by this updater.
195     *
196     * @param obj An object whose field to get and set
197     * @return the updated value
198     */
199     public long incrementAndGet(T obj) {
200     for (;;) {
201     long current = get(obj);
202     long next = current + 1;
203     if (compareAndSet(obj, current, next))
204     return next;
205     }
206     }
207    
208     /**
209     * Atomically decrements by one the current value of the field of the
210     * given object managed by this updater.
211     *
212     * @param obj An object whose field to get and set
213     * @return the updated value
214     */
215     public long decrementAndGet(T obj) {
216     for (;;) {
217     long current = get(obj);
218     long next = current - 1;
219     if (compareAndSet(obj, current, next))
220     return next;
221     }
222     }
223    
224     /**
225     * Atomically adds the given value to the current value of the field of
226     * the given object managed by this updater.
227     *
228     * @param obj An object whose field to get and set
229     * @param delta the value to add
230     * @return the updated value
231     */
232     public long addAndGet(T obj, long delta) {
233     for (;;) {
234     long current = get(obj);
235     long next = current + delta;
236     if (compareAndSet(obj, current, next))
237     return next;
238     }
239     }
240    
241     private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
242     private static final Unsafe unsafe = Unsafe.getUnsafe();
243     private final long offset;
244     private final Class<T> tclass;
245     private final Class<?> cclass;
246    
247     CASUpdater(final Class<T> tclass, final String fieldName) {
248     final Field field;
249     final Class<?> caller;
250     final int modifiers;
251     try {
252     field = AccessController.doPrivileged(
253     new PrivilegedExceptionAction<Field>() {
254     public Field run() throws NoSuchFieldException {
255     return tclass.getDeclaredField(fieldName);
256     }
257     });
258     caller = sun.reflect.Reflection.getCallerClass(3);
259     modifiers = field.getModifiers();
260     sun.reflect.misc.ReflectUtil.ensureMemberAccess(
261     caller, tclass, null, modifiers);
262     ClassLoader cl = tclass.getClassLoader();
263     ClassLoader ccl = caller.getClassLoader();
264     if ((ccl != null) && (ccl != cl) &&
265     ((cl == null) || !isAncestor(cl, ccl))) {
266     sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
267     }
268     } catch (PrivilegedActionException pae) {
269     throw new RuntimeException(pae.getException());
270     } catch (Exception ex) {
271     throw new RuntimeException(ex);
272     }
273    
274     Class<?> fieldt = field.getType();
275     if (fieldt != long.class)
276     throw new IllegalArgumentException("Must be long type");
277    
278     if (!Modifier.isVolatile(modifiers))
279     throw new IllegalArgumentException("Must be volatile type");
280    
281     this.cclass = (Modifier.isProtected(modifiers) &&
282     caller != tclass) ? caller : null;
283     this.tclass = tclass;
284     offset = unsafe.objectFieldOffset(field);
285     }
286    
287     private void fullCheck(T obj) {
288     if (!tclass.isInstance(obj))
289     throw new ClassCastException();
290     if (cclass != null)
291     ensureProtectedAccess(obj);
292     }
293    
294     public boolean compareAndSet(T obj, long expect, long update) {
295     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
296     return unsafe.compareAndSwapLong(obj, offset, expect, update);
297     }
298    
299     public boolean weakCompareAndSet(T obj, long expect, long update) {
300     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
301     return unsafe.compareAndSwapLong(obj, offset, expect, update);
302     }
303    
304     public void set(T obj, long newValue) {
305     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
306     unsafe.putLongVolatile(obj, offset, newValue);
307     }
308    
309     public void lazySet(T obj, long newValue) {
310     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
311     unsafe.putOrderedLong(obj, offset, newValue);
312     }
313    
314     public long get(T obj) {
315     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
316     return unsafe.getLongVolatile(obj, offset);
317     }
318    
319     private void ensureProtectedAccess(T obj) {
320     if (cclass.isInstance(obj)) {
321     return;
322     }
323     throw new RuntimeException(
324     new IllegalAccessException("Class " +
325     cclass.getName() +
326     " can not access a protected member of class " +
327     tclass.getName() +
328     " using an instance of " +
329     obj.getClass().getName()
330     )
331     );
332     }
333     }
334    
335    
336     private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
337     private static final Unsafe unsafe = Unsafe.getUnsafe();
338     private final long offset;
339     private final Class<T> tclass;
340     private final Class<?> cclass;
341    
342     LockedUpdater(final Class<T> tclass, final String fieldName) {
343     Field field = null;
344     Class<?> caller = null;
345     int modifiers = 0;
346     try {
347     field = AccessController.doPrivileged(
348     new PrivilegedExceptionAction<Field>() {
349     public Field run() throws NoSuchFieldException {
350     return tclass.getDeclaredField(fieldName);
351     }
352     });
353     caller = sun.reflect.Reflection.getCallerClass(3);
354     modifiers = field.getModifiers();
355     sun.reflect.misc.ReflectUtil.ensureMemberAccess(
356     caller, tclass, null, modifiers);
357     ClassLoader cl = tclass.getClassLoader();
358     ClassLoader ccl = caller.getClassLoader();
359     if ((ccl != null) && (ccl != cl) &&
360     ((cl == null) || !isAncestor(cl, ccl))) {
361     sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
362     }
363     } catch (PrivilegedActionException pae) {
364     throw new RuntimeException(pae.getException());
365     } catch (Exception ex) {
366     throw new RuntimeException(ex);
367     }
368    
369     Class<?> fieldt = field.getType();
370     if (fieldt != long.class)
371     throw new IllegalArgumentException("Must be long type");
372    
373     if (!Modifier.isVolatile(modifiers))
374     throw new IllegalArgumentException("Must be volatile type");
375    
376     this.cclass = (Modifier.isProtected(modifiers) &&
377     caller != tclass) ? caller : null;
378     this.tclass = tclass;
379     offset = unsafe.objectFieldOffset(field);
380     }
381    
382     private void fullCheck(T obj) {
383     if (!tclass.isInstance(obj))
384     throw new ClassCastException();
385     if (cclass != null)
386     ensureProtectedAccess(obj);
387     }
388    
389     public boolean compareAndSet(T obj, long expect, long update) {
390     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
391     synchronized (this) {
392     long v = unsafe.getLong(obj, offset);
393     if (v != expect)
394     return false;
395     unsafe.putLong(obj, offset, update);
396     return true;
397     }
398     }
399    
400     public boolean weakCompareAndSet(T obj, long expect, long update) {
401     return compareAndSet(obj, expect, update);
402     }
403    
404     public void set(T obj, long newValue) {
405     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
406     synchronized (this) {
407     unsafe.putLong(obj, offset, newValue);
408     }
409     }
410    
411     public void lazySet(T obj, long newValue) {
412     set(obj, newValue);
413     }
414    
415     public long get(T obj) {
416     if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
417     synchronized (this) {
418     return unsafe.getLong(obj, offset);
419     }
420     }
421    
422     private void ensureProtectedAccess(T obj) {
423     if (cclass.isInstance(obj)) {
424     return;
425     }
426     throw new RuntimeException(
427     new IllegalAccessException("Class " +
428     cclass.getName() +
429     " can not access a protected member of class " +
430     tclass.getName() +
431     " using an instance of " +
432     obj.getClass().getName()
433     )
434     );
435     }
436     }
437    
438     /**
439     * Returns true if the second classloader can be found in the first
440     * classloader's delegation chain.
441     * Equivalent to the inaccessible: first.isAncestor(second).
442     */
443     private static boolean isAncestor(ClassLoader first, ClassLoader second) {
444     ClassLoader acl = first;
445     do {
446     acl = acl.getParent();
447     if (second == acl) {
448     return true;
449     }
450     } while (acl != null);
451     return false;
452     }
453     }