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.6
Committed: Sun Jan 18 20:17:32 2015 UTC (9 years, 5 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.5: +1 -0 lines
Log Message:
exactly one blank line before and after package statements

File Contents

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