blob: 8b9c744fe543ae3327af746b58c1a8a0ab8d758c [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 *
4 * This code is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 2 only, as
6 * published by the Free Software Foundation. Sun designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Sun in the LICENSE file that accompanied this code.
9 *
10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * version 2 for more details (a copy is included in the LICENSE file that
14 * accompanied this code).
15 *
16 * You should have received a copy of the GNU General Public License version
17 * 2 along with this work; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 *
20 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21 * CA 95054 USA or visit www.sun.com if you need additional information or
22 * have any questions.
23 */
24
25/*
26 * This file is available under and governed by the GNU General Public
27 * License version 2 only, as published by the Free Software Foundation.
28 * However, the following notice accompanied the original version of this
29 * file:
30 *
31 * Written by Doug Lea with assistance from members of JCP JSR-166
32 * Expert Group and released to the public domain, as explained at
33 * http://creativecommons.org/licenses/publicdomain
34 */
35
36package java.util.concurrent.atomic;
37import sun.misc.Unsafe;
38import java.lang.reflect.*;
39
40/**
41 * A reflection-based utility that enables atomic updates to
42 * designated {@code volatile int} fields of designated classes.
43 * This class is designed for use in atomic data structures in which
44 * several fields of the same node are independently subject to atomic
45 * updates.
46 *
47 * <p>Note that the guarantees of the {@code compareAndSet}
48 * method in this class are weaker than in other atomic classes.
49 * Because this class cannot ensure that all uses of the field
50 * are appropriate for purposes of atomic access, it can
51 * guarantee atomicity only with respect to other invocations of
52 * {@code compareAndSet} and {@code set} on the same updater.
53 *
54 * @since 1.5
55 * @author Doug Lea
56 * @param <T> The type of the object holding the updatable field
57 */
58public abstract class AtomicIntegerFieldUpdater<T> {
59 /**
60 * Creates and returns an updater for objects with the given field.
61 * The Class argument is needed to check that reflective types and
62 * generic types match.
63 *
64 * @param tclass the class of the objects holding the field
65 * @param fieldName the name of the field to be updated
66 * @return the updater
67 * @throws IllegalArgumentException if the field is not a
68 * volatile integer type
69 * @throws RuntimeException with a nested reflection-based
70 * exception if the class does not hold field or is the wrong type
71 */
72 public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
73 return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName);
74 }
75
76 /**
77 * Protected do-nothing constructor for use by subclasses.
78 */
79 protected AtomicIntegerFieldUpdater() {
80 }
81
82 /**
83 * Atomically sets the field of the given object managed by this updater
84 * to the given updated value if the current value {@code ==} the
85 * expected value. This method is guaranteed to be atomic with respect to
86 * other calls to {@code compareAndSet} and {@code set}, but not
87 * necessarily with respect to other changes in the field.
88 *
89 * @param obj An object whose field to conditionally set
90 * @param expect the expected value
91 * @param update the new value
92 * @return true if successful
93 * @throws ClassCastException if {@code obj} is not an instance
94 * of the class possessing the field established in the constructor
95 */
96 public abstract boolean compareAndSet(T obj, int expect, int update);
97
98 /**
99 * Atomically sets the field of the given object managed by this updater
100 * to the given updated value if the current value {@code ==} the
101 * expected value. This method is guaranteed to be atomic with respect to
102 * other calls to {@code compareAndSet} and {@code set}, but not
103 * necessarily with respect to other changes in the field.
104 *
105 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
106 * and does not provide ordering guarantees, so is only rarely an
107 * appropriate alternative to {@code compareAndSet}.
108 *
109 * @param obj An object whose field to conditionally set
110 * @param expect the expected value
111 * @param update the new value
112 * @return true if successful
113 * @throws ClassCastException if {@code obj} is not an instance
114 * of the class possessing the field established in the constructor
115 */
116 public abstract boolean weakCompareAndSet(T obj, int expect, int update);
117
118 /**
119 * Sets the field of the given object managed by this updater to the
120 * given updated value. This operation is guaranteed to act as a volatile
121 * store with respect to subsequent invocations of {@code compareAndSet}.
122 *
123 * @param obj An object whose field to set
124 * @param newValue the new value
125 */
126 public abstract void set(T obj, int newValue);
127
128 /**
129 * Eventually sets the field of the given object managed by this
130 * updater to the given updated value.
131 *
132 * @param obj An object whose field to set
133 * @param newValue the new value
134 * @since 1.6
135 */
136 public abstract void lazySet(T obj, int newValue);
137
138
139 /**
140 * Gets the current value held in the field of the given object managed
141 * by this updater.
142 *
143 * @param obj An object whose field to get
144 * @return the current value
145 */
146 public abstract int get(T obj);
147
148 /**
149 * Atomically sets the field of the given object managed by this updater
150 * to the given value and returns the old value.
151 *
152 * @param obj An object whose field to get and set
153 * @param newValue the new value
154 * @return the previous value
155 */
156 public int getAndSet(T obj, int newValue) {
157 for (;;) {
158 int current = get(obj);
159 if (compareAndSet(obj, current, newValue))
160 return current;
161 }
162 }
163
164 /**
165 * Atomically increments 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 getAndIncrement(T obj) {
172 for (;;) {
173 int current = get(obj);
174 int next = current + 1;
175 if (compareAndSet(obj, current, next))
176 return current;
177 }
178 }
179
180 /**
181 * Atomically decrements by one the current value of the field of the
182 * given object managed by this updater.
183 *
184 * @param obj An object whose field to get and set
185 * @return the previous value
186 */
187 public int getAndDecrement(T obj) {
188 for (;;) {
189 int current = get(obj);
190 int next = current - 1;
191 if (compareAndSet(obj, current, next))
192 return current;
193 }
194 }
195
196 /**
197 * Atomically adds the given value to the current value of the field of
198 * the given object managed by this updater.
199 *
200 * @param obj An object whose field to get and set
201 * @param delta the value to add
202 * @return the previous value
203 */
204 public int getAndAdd(T obj, int delta) {
205 for (;;) {
206 int current = get(obj);
207 int next = current + delta;
208 if (compareAndSet(obj, current, next))
209 return current;
210 }
211 }
212
213 /**
214 * Atomically increments 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 incrementAndGet(T obj) {
221 for (;;) {
222 int current = get(obj);
223 int next = current + 1;
224 if (compareAndSet(obj, current, next))
225 return next;
226 }
227 }
228
229 /**
230 * Atomically decrements by one the current value of the field of the
231 * given object managed by this updater.
232 *
233 * @param obj An object whose field to get and set
234 * @return the updated value
235 */
236 public int decrementAndGet(T obj) {
237 for (;;) {
238 int current = get(obj);
239 int next = current - 1;
240 if (compareAndSet(obj, current, next))
241 return next;
242 }
243 }
244
245 /**
246 * Atomically adds the given value to the current value of the field of
247 * the given object managed by this updater.
248 *
249 * @param obj An object whose field to get and set
250 * @param delta the value to add
251 * @return the updated value
252 */
253 public int addAndGet(T obj, int delta) {
254 for (;;) {
255 int current = get(obj);
256 int next = current + delta;
257 if (compareAndSet(obj, current, next))
258 return next;
259 }
260 }
261
262 /**
263 * Standard hotspot implementation using intrinsics
264 */
265 private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> {
266 private static final Unsafe unsafe = Unsafe.getUnsafe();
267 private final long offset;
268 private final Class<T> tclass;
269 private final Class cclass;
270
271 AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName) {
272 Field field = null;
273 Class caller = null;
274 int modifiers = 0;
275 try {
276 field = tclass.getDeclaredField(fieldName);
277 caller = sun.reflect.Reflection.getCallerClass(3);
278 modifiers = field.getModifiers();
279 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
280 caller, tclass, null, modifiers);
281 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
282 } catch(Exception ex) {
283 throw new RuntimeException(ex);
284 }
285
286 Class fieldt = field.getType();
287 if (fieldt != int.class)
288 throw new IllegalArgumentException("Must be integer type");
289
290 if (!Modifier.isVolatile(modifiers))
291 throw new IllegalArgumentException("Must be volatile type");
292
293 this.cclass = (Modifier.isProtected(modifiers) &&
294 caller != tclass) ? caller : null;
295 this.tclass = tclass;
296 offset = unsafe.objectFieldOffset(field);
297 }
298
299 private void fullCheck(T obj) {
300 if (!tclass.isInstance(obj))
301 throw new ClassCastException();
302 if (cclass != null)
303 ensureProtectedAccess(obj);
304 }
305
306 public boolean compareAndSet(T obj, int expect, int update) {
307 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
308 return unsafe.compareAndSwapInt(obj, offset, expect, update);
309 }
310
311 public boolean weakCompareAndSet(T obj, int expect, int update) {
312 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
313 return unsafe.compareAndSwapInt(obj, offset, expect, update);
314 }
315
316 public void set(T obj, int newValue) {
317 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
318 unsafe.putIntVolatile(obj, offset, newValue);
319 }
320
321 public void lazySet(T obj, int newValue) {
322 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
323 unsafe.putOrderedInt(obj, offset, newValue);
324 }
325
326 public final int get(T obj) {
327 if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
328 return unsafe.getIntVolatile(obj, offset);
329 }
330
331 private void ensureProtectedAccess(T obj) {
332 if (cclass.isInstance(obj)) {
333 return;
334 }
335 throw new RuntimeException(
336 new IllegalAccessException("Class " +
337 cclass.getName() +
338 " can not access a protected member of class " +
339 tclass.getName() +
340 " using an instance of " +
341 obj.getClass().getName()
342 )
343 );
344 }
345 }
346}