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 int} 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 AtomicIntegerFieldUpdater<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 integer 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> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) { |
52 |
return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName); |
53 |
} |
54 |
|
55 |
/** |
56 |
* Protected do-nothing constructor for use by subclasses. |
57 |
*/ |
58 |
protected AtomicIntegerFieldUpdater() { |
59 |
} |
60 |
|
61 |
/** |
62 |
* Atomically sets the field of the given object managed by this updater |
63 |
* to the given updated value if the current value {@code ==} the |
64 |
* expected value. This method is guaranteed to be atomic with respect to |
65 |
* other calls to {@code compareAndSet} and {@code set}, but not |
66 |
* necessarily with respect to other changes in the field. |
67 |
* |
68 |
* @param obj An object whose field to conditionally set |
69 |
* @param expect the expected value |
70 |
* @param update the new value |
71 |
* @return true if successful |
72 |
* @throws ClassCastException if {@code obj} is not an instance |
73 |
* of the class possessing the field established in the constructor |
74 |
*/ |
75 |
public abstract boolean compareAndSet(T obj, int expect, int update); |
76 |
|
77 |
/** |
78 |
* Atomically sets the field of the given object managed by this updater |
79 |
* to the given updated value if the current value {@code ==} the |
80 |
* expected value. This method is guaranteed to be atomic with respect to |
81 |
* other calls to {@code compareAndSet} and {@code set}, but not |
82 |
* necessarily with respect to other changes in the field. |
83 |
* |
84 |
* <p><a href="package-summary.html#weakCompareAndSet">May fail |
85 |
* spuriously and does not provide ordering guarantees</a>, so is |
86 |
* only rarely an appropriate alternative to {@code compareAndSet}. |
87 |
* |
88 |
* @param obj An object whose field to conditionally set |
89 |
* @param expect the expected value |
90 |
* @param update the new value |
91 |
* @return true if successful |
92 |
* @throws ClassCastException if {@code obj} is not an instance |
93 |
* of the class possessing the field established in the constructor |
94 |
*/ |
95 |
public abstract boolean weakCompareAndSet(T obj, int expect, int update); |
96 |
|
97 |
/** |
98 |
* Sets the field of the given object managed by this updater to the |
99 |
* given updated value. This operation is guaranteed to act as a volatile |
100 |
* store with respect to subsequent invocations of {@code compareAndSet}. |
101 |
* |
102 |
* @param obj An object whose field to set |
103 |
* @param newValue the new value |
104 |
*/ |
105 |
public abstract void set(T obj, int newValue); |
106 |
|
107 |
/** |
108 |
* Eventually sets the field of the given object managed by this |
109 |
* updater to the given updated value. |
110 |
* |
111 |
* @param obj An object whose field to set |
112 |
* @param newValue the new value |
113 |
* @since 1.6 |
114 |
*/ |
115 |
public abstract void lazySet(T obj, int newValue); |
116 |
|
117 |
/** |
118 |
* Gets the current value held in the field of the given object managed |
119 |
* by this updater. |
120 |
* |
121 |
* @param obj An object whose field to get |
122 |
* @return the current value |
123 |
*/ |
124 |
public abstract int get(T obj); |
125 |
|
126 |
/** |
127 |
* Atomically sets the field of the given object managed by this updater |
128 |
* to the given value and returns the old value. |
129 |
* |
130 |
* @param obj An object whose field to get and set |
131 |
* @param newValue the new value |
132 |
* @return the previous value |
133 |
*/ |
134 |
public int getAndSet(T obj, int newValue) { |
135 |
for (;;) { |
136 |
int current = get(obj); |
137 |
if (compareAndSet(obj, current, newValue)) |
138 |
return current; |
139 |
} |
140 |
} |
141 |
|
142 |
/** |
143 |
* Atomically increments by one the current value of the field of the |
144 |
* given object managed by this updater. |
145 |
* |
146 |
* @param obj An object whose field to get and set |
147 |
* @return the previous value |
148 |
*/ |
149 |
public int getAndIncrement(T obj) { |
150 |
for (;;) { |
151 |
int current = get(obj); |
152 |
int next = current + 1; |
153 |
if (compareAndSet(obj, current, next)) |
154 |
return current; |
155 |
} |
156 |
} |
157 |
|
158 |
/** |
159 |
* Atomically decrements by one the current value of the field of the |
160 |
* given object managed by this updater. |
161 |
* |
162 |
* @param obj An object whose field to get and set |
163 |
* @return the previous value |
164 |
*/ |
165 |
public int getAndDecrement(T obj) { |
166 |
for (;;) { |
167 |
int current = get(obj); |
168 |
int next = current - 1; |
169 |
if (compareAndSet(obj, current, next)) |
170 |
return current; |
171 |
} |
172 |
} |
173 |
|
174 |
/** |
175 |
* Atomically adds the given value to the current value of the field of |
176 |
* the given object managed by this updater. |
177 |
* |
178 |
* @param obj An object whose field to get and set |
179 |
* @param delta the value to add |
180 |
* @return the previous value |
181 |
*/ |
182 |
public int getAndAdd(T obj, int delta) { |
183 |
for (;;) { |
184 |
int current = get(obj); |
185 |
int next = current + delta; |
186 |
if (compareAndSet(obj, current, next)) |
187 |
return current; |
188 |
} |
189 |
} |
190 |
|
191 |
/** |
192 |
* Atomically increments by one the current value of the field of the |
193 |
* given object managed by this updater. |
194 |
* |
195 |
* @param obj An object whose field to get and set |
196 |
* @return the updated value |
197 |
*/ |
198 |
public int incrementAndGet(T obj) { |
199 |
for (;;) { |
200 |
int current = get(obj); |
201 |
int next = current + 1; |
202 |
if (compareAndSet(obj, current, next)) |
203 |
return next; |
204 |
} |
205 |
} |
206 |
|
207 |
/** |
208 |
* Atomically decrements by one the current value of the field of the |
209 |
* given object managed by this updater. |
210 |
* |
211 |
* @param obj An object whose field to get and set |
212 |
* @return the updated value |
213 |
*/ |
214 |
public int decrementAndGet(T obj) { |
215 |
for (;;) { |
216 |
int current = get(obj); |
217 |
int next = current - 1; |
218 |
if (compareAndSet(obj, current, next)) |
219 |
return next; |
220 |
} |
221 |
} |
222 |
|
223 |
/** |
224 |
* Atomically adds the given value to the current value of the field of |
225 |
* the given object managed by this updater. |
226 |
* |
227 |
* @param obj An object whose field to get and set |
228 |
* @param delta the value to add |
229 |
* @return the updated value |
230 |
*/ |
231 |
public int addAndGet(T obj, int delta) { |
232 |
for (;;) { |
233 |
int current = get(obj); |
234 |
int next = current + delta; |
235 |
if (compareAndSet(obj, current, next)) |
236 |
return next; |
237 |
} |
238 |
} |
239 |
|
240 |
/** |
241 |
* Standard hotspot implementation using intrinsics |
242 |
*/ |
243 |
private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<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 |
AtomicIntegerFieldUpdaterImpl(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 != int.class) |
278 |
throw new IllegalArgumentException("Must be integer 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 |
/** |
290 |
* Returns true if the second classloader can be found in the first |
291 |
* classloader's delegation chain. |
292 |
* Equivalent to the inaccessible: first.isAncestor(second). |
293 |
*/ |
294 |
private static boolean isAncestor(ClassLoader first, ClassLoader second) { |
295 |
ClassLoader acl = first; |
296 |
do { |
297 |
acl = acl.getParent(); |
298 |
if (second == acl) { |
299 |
return true; |
300 |
} |
301 |
} while (acl != null); |
302 |
return false; |
303 |
} |
304 |
|
305 |
private void fullCheck(T obj) { |
306 |
if (!tclass.isInstance(obj)) |
307 |
throw new ClassCastException(); |
308 |
if (cclass != null) |
309 |
ensureProtectedAccess(obj); |
310 |
} |
311 |
|
312 |
public boolean compareAndSet(T obj, int expect, int update) { |
313 |
if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); |
314 |
return unsafe.compareAndSwapInt(obj, offset, expect, update); |
315 |
} |
316 |
|
317 |
public boolean weakCompareAndSet(T obj, int expect, int update) { |
318 |
if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); |
319 |
return unsafe.compareAndSwapInt(obj, offset, expect, update); |
320 |
} |
321 |
|
322 |
public void set(T obj, int newValue) { |
323 |
if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); |
324 |
unsafe.putIntVolatile(obj, offset, newValue); |
325 |
} |
326 |
|
327 |
public void lazySet(T obj, int newValue) { |
328 |
if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); |
329 |
unsafe.putOrderedInt(obj, offset, newValue); |
330 |
} |
331 |
|
332 |
public final int get(T obj) { |
333 |
if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj); |
334 |
return unsafe.getIntVolatile(obj, offset); |
335 |
} |
336 |
|
337 |
private void ensureProtectedAccess(T obj) { |
338 |
if (cclass.isInstance(obj)) { |
339 |
return; |
340 |
} |
341 |
throw new RuntimeException( |
342 |
new IllegalAccessException("Class " + |
343 |
cclass.getName() + |
344 |
" can not access a protected member of class " + |
345 |
tclass.getName() + |
346 |
" using an instance of " + |
347 |
obj.getClass().getName() |
348 |
) |
349 |
); |
350 |
} |
351 |
} |
352 |
} |