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