KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > util > concurrent > atomic > AtomicLongFieldUpdater


1 /*
2  * @(#)AtomicLongFieldUpdater.java 1.8 05/08/09
3  *
4  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.util.concurrent.atomic;
9 import sun.misc.Unsafe;
10 import java.lang.reflect.*;
11
12 /**
13  * A reflection-based utility that enables atomic updates to
14  * designated <tt>volatile long</tt> fields of designated classes.
15  * This class is designed for use in atomic data structures in which
16  * several fields of the same node are independently subject to atomic
17  * updates.
18  *
19  * <p> Note that the guarantees of the <tt>compareAndSet</tt> method
20  * in this class are weaker than in other atomic classes. Because this
21  * class cannot ensure that all uses of the field are appropriate for
22  * purposes of atomic access, it can guarantee atomicity and volatile
23  * semantics only with respect to other invocations of
24  * <tt>compareAndSet</tt> and <tt>set</tt>.
25  *
26  * @since 1.5
27  * @author Doug Lea
28  * @param <T> The type of the object holding the updatable field
29  */

30 public abstract class AtomicLongFieldUpdater<T> {
31     /**
32      * Creates an updater for objects with the given field. The Class
33      * argument is needed to check that reflective types and generic
34      * types match.
35      * @param tclass the class of the objects holding the field
36      * @param fieldName the name of the field to be updated.
37      * @return the updater
38      * @throws IllegalArgumentException if the field is not a
39      * volatile long type.
40      * @throws RuntimeException with a nested reflection-based
41      * exception if the class does not hold field or is the wrong type.
42      */

43     public static <U> AtomicLongFieldUpdater JavaDoc<U> newUpdater(Class JavaDoc<U> tclass, String JavaDoc fieldName) {
44         if (AtomicLong.VM_SUPPORTS_LONG_CAS)
45             return new CASUpdater<U>(tclass, fieldName);
46         else
47             return new LockedUpdater<U>(tclass, fieldName);
48     }
49
50     /**
51      * Protected do-nothing constructor for use by subclasses.
52      */

53     protected AtomicLongFieldUpdater() {
54     }
55
56     /**
57      * Atomically set the value of the field of the given object managed
58      * by this Updater to the given updated value if the current value
59      * <tt>==</tt> the expected value. This method is guaranteed to be
60      * atomic with respect to other calls to <tt>compareAndSet</tt> and
61      * <tt>set</tt>, but not necessarily with respect to other
62      * changes in the field.
63      * @param obj An object whose field to conditionally set
64      * @param expect the expected value
65      * @param update the new value
66      * @return true if successful.
67      * @throws ClassCastException if <tt>obj</tt> is not an instance
68      * of the class possessing the field established in the constructor.
69      */

70
71     public abstract boolean compareAndSet(T obj, long expect, long update);
72
73     /**
74      * Atomically set the value of the field of the given object managed
75      * by this Updater to the given updated value if the current value
76      * <tt>==</tt> the expected value. This method is guaranteed to be
77      * atomic with respect to other calls to <tt>compareAndSet</tt> and
78      * <tt>set</tt>, but not necessarily with respect to other
79      * changes in the field, and may fail spuriously.
80      * @param obj An object whose field to conditionally set
81      * @param expect the expected value
82      * @param update the new value
83      * @return true if successful.
84      * @throws ClassCastException if <tt>obj</tt> is not an instance
85      * of the class possessing the field established in the constructor.
86      */

87
88     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
89
90     /**
91      * Set the field of the given object managed by this updater. This
92      * operation is guaranteed to act as a volatile store with respect
93      * to subsequent invocations of <tt>compareAndSet</tt>.
94      * @param obj An object whose field to set
95      * @param newValue the new value
96      */

97     public abstract void set(T obj, long newValue);
98
99     /**
100      * Get the current value held in the field by the given object.
101      * @param obj An object whose field to get
102      * @return the current value
103      */

104     public abstract long get(T obj);
105
106     /**
107      * Set to the given value and return the old value.
108      *
109      * @param obj An object whose field to get and set
110      * @param newValue the new value
111      * @return the previous value
112      */

113     public long getAndSet(T obj, long newValue) {
114         for (;;) {
115             long current = get(obj);
116             if (compareAndSet(obj, current, newValue))
117                 return current;
118         }
119     }
120
121     /**
122      * Atomically increment by one the current value.
123      * @param obj An object whose field to get and set
124      * @return the previous value;
125      */

126     public long getAndIncrement(T obj) {
127         for (;;) {
128             long current = get(obj);
129             long next = current + 1;
130             if (compareAndSet(obj, current, next))
131                 return current;
132         }
133     }
134
135
136     /**
137      * Atomically decrement by one the current value.
138      * @param obj An object whose field to get and set
139      * @return the previous value;
140      */

141     public long getAndDecrement(T obj) {
142         for (;;) {
143             long current = get(obj);
144             long next = current - 1;
145             if (compareAndSet(obj, current, next))
146                 return current;
147         }
148     }
149
150
151     /**
152      * Atomically add the given value to current value.
153      * @param obj An object whose field to get and set
154      * @param delta the value to add
155      * @return the previous value;
156      */

157     public long getAndAdd(T obj, long delta) {
158         for (;;) {
159             long current = get(obj);
160             long next = current + delta;
161             if (compareAndSet(obj, current, next))
162                 return current;
163         }
164     }
165
166     /**
167      * Atomically increment by one the current value.
168      * @param obj An object whose field to get and set
169      * @return the updated value;
170      */

171     public long incrementAndGet(T obj) {
172         for (;;) {
173             long current = get(obj);
174             long next = current + 1;
175             if (compareAndSet(obj, current, next))
176                 return next;
177         }
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     /**
197      * Atomically add the given value to current value.
198      * @param obj An object whose field to get and set
199      * @param delta the value to add
200      * @return the updated value;
201      */

202     public long addAndGet(T obj, long delta) {
203         for (;;) {
204             long current = get(obj);
205             long next = current + delta;
206             if (compareAndSet(obj, current, next))
207                 return next;
208         }
209     }
210
211     private static class CASUpdater<T> extends AtomicLongFieldUpdater JavaDoc<T> {
212         private static final Unsafe unsafe = Unsafe.getUnsafe();
213         private final long offset;
214         private final Class JavaDoc<T> tclass;
215         private final Class JavaDoc cclass;
216
217         CASUpdater(Class JavaDoc<T> tclass, String JavaDoc fieldName) {
218             Field field = null;
219         Class JavaDoc caller = null;
220         int modifiers = 0;
221             try {
222                 field = tclass.getDeclaredField(fieldName);
223         caller = sun.reflect.Reflection.getCallerClass(3);
224         modifiers = field.getModifiers();
225                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
226                     caller, tclass, null, modifiers);
227         sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
228             } catch(Exception JavaDoc ex) {
229                 throw new RuntimeException JavaDoc(ex);
230             }
231
232             Class JavaDoc fieldt = field.getType();
233             if (fieldt != long.class)
234                 throw new IllegalArgumentException JavaDoc("Must be long type");
235
236             if (!Modifier.isVolatile(modifiers))
237                 throw new IllegalArgumentException JavaDoc("Must be volatile type");
238
239         this.cclass = (Modifier.isProtected(modifiers) &&
240                caller != tclass) ? caller : null;
241             this.tclass = tclass;
242             offset = unsafe.objectFieldOffset(field);
243         }
244
245         public boolean compareAndSet(T obj, long expect, long update) {
246             if (!tclass.isInstance(obj))
247                 throw new ClassCastException JavaDoc();
248         if (cclass != null)
249             ensureProtectedAccess(obj);
250             return unsafe.compareAndSwapLong(obj, offset, expect, update);
251         }
252
253         public boolean weakCompareAndSet(T obj, long expect, long update) {
254             if (!tclass.isInstance(obj))
255                 throw new ClassCastException JavaDoc();
256         if (cclass != null)
257             ensureProtectedAccess(obj);
258             return unsafe.compareAndSwapLong(obj, offset, expect, update);
259         }
260
261         public void set(T obj, long newValue) {
262             if (!tclass.isInstance(obj))
263                 throw new ClassCastException JavaDoc();
264         if (cclass != null)
265             ensureProtectedAccess(obj);
266             unsafe.putLongVolatile(obj, offset, newValue);
267         }
268
269         public long get(T obj) {
270             if (!tclass.isInstance(obj))
271                 throw new ClassCastException JavaDoc();
272         if (cclass != null)
273             ensureProtectedAccess(obj);
274             return unsafe.getLongVolatile(obj, offset);
275         }
276
277     private void ensureProtectedAccess(T obj) {
278         if (cclass.isInstance(obj)) {
279         return;
280         }
281         throw new RuntimeException JavaDoc (
282                 new IllegalAccessException JavaDoc("Class " +
283             cclass.getName() +
284                     " can not access a protected member of class " +
285                     tclass.getName() +
286             " using an instance of " +
287                     obj.getClass().getName()
288         )
289         );
290     }
291     }
292
293
294     private static class LockedUpdater<T> extends AtomicLongFieldUpdater JavaDoc<T> {
295         private static final Unsafe unsafe = Unsafe.getUnsafe();
296         private final long offset;
297         private final Class JavaDoc<T> tclass;
298         private final Class JavaDoc cclass;
299
300         LockedUpdater(Class JavaDoc<T> tclass, String JavaDoc fieldName) {
301             Field field = null;
302         Class JavaDoc caller = null;
303         int modifiers = 0;
304             try {
305                 field = tclass.getDeclaredField(fieldName);
306         caller = sun.reflect.Reflection.getCallerClass(3);
307         modifiers = field.getModifiers();
308                 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
309                     caller, tclass, null, modifiers);
310         sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
311             } catch(Exception JavaDoc ex) {
312                 throw new RuntimeException JavaDoc(ex);
313             }
314
315             Class JavaDoc fieldt = field.getType();
316             if (fieldt != long.class)
317                 throw new IllegalArgumentException JavaDoc("Must be long type");
318
319             if (!Modifier.isVolatile(modifiers))
320                 throw new IllegalArgumentException JavaDoc("Must be volatile type");
321
322         this.cclass = (Modifier.isProtected(modifiers) &&
323                caller != tclass) ? caller : null;
324             this.tclass = tclass;
325             offset = unsafe.objectFieldOffset(field);
326         }
327
328         public boolean compareAndSet(T obj, long expect, long update) {
329             if (!tclass.isInstance(obj))
330                 throw new ClassCastException JavaDoc();
331         if (cclass != null)
332             ensureProtectedAccess(obj);
333             synchronized(this) {
334                 long v = unsafe.getLong(obj, offset);
335                 if (v != expect)
336                     return false;
337                 unsafe.putLong(obj, offset, update);
338                 return true;
339             }
340         }
341
342         public boolean weakCompareAndSet(T obj, long expect, long update) {
343             return compareAndSet(obj, expect, update);
344         }
345
346         public void set(T obj, long newValue) {
347             if (!tclass.isInstance(obj))
348                 throw new ClassCastException JavaDoc();
349         if (cclass != null)
350             ensureProtectedAccess(obj);
351             synchronized(this) {
352                 unsafe.putLong(obj, offset, newValue);
353             }
354         }
355
356         public long get(T obj) {
357             if (!tclass.isInstance(obj))
358                 throw new ClassCastException JavaDoc();
359         if (cclass != null)
360             ensureProtectedAccess(obj);
361             synchronized(this) {
362                 return unsafe.getLong(obj, offset);
363             }
364         }
365
366     private void ensureProtectedAccess(T obj) {
367         if (cclass.isInstance(obj)) {
368         return;
369         }
370         throw new RuntimeException JavaDoc (
371                 new IllegalAccessException JavaDoc("Class " +
372             cclass.getName() +
373                     " can not access a protected member of class " +
374                     tclass.getName() +
375             " using an instance of " +
376                     obj.getClass().getName()
377         )
378         );
379     }
380     }
381 }
382
383
Popular Tags