ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk7/java/util/concurrent/atomic/AtomicIntegerFieldUpdater.java
Revision: 1.4
Committed: Sun Jan 18 20:17:32 2015 UTC (9 years, 5 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.3: +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 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 }