AtomicIntegerFieldUpdater.java revision 51b1b6997fd3f980076b8081f7f1165ccc2a4008
1/*
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.  Oracle designates this
7 * particular file as subject to the "Classpath" exception as provided
8 * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 * or visit www.oracle.com if you need additional information or have any
22 * 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/publicdomain/zero/1.0/
34 */
35
36package java.util.concurrent.atomic;
37import java.lang.reflect.*;
38import sun.misc.Unsafe;
39import sun.reflect.CallerSensitive;
40import sun.reflect.Reflection;
41
42/**
43 * A reflection-based utility that enables atomic updates to
44 * designated {@code volatile int} fields of designated classes.
45 * This class is designed for use in atomic data structures in which
46 * several fields of the same node are independently subject to atomic
47 * updates.
48 *
49 * <p>Note that the guarantees of the {@code compareAndSet}
50 * method in this class are weaker than in other atomic classes.
51 * Because this class cannot ensure that all uses of the field
52 * are appropriate for purposes of atomic access, it can
53 * guarantee atomicity only with respect to other invocations of
54 * {@code compareAndSet} and {@code set} on the same updater.
55 *
56 * @since 1.5
57 * @author Doug Lea
58 * @param <T> The type of the object holding the updatable field
59 */
60public abstract class  AtomicIntegerFieldUpdater<T> {
61    /**
62     * Creates and returns an updater for objects with the given field.
63     * The Class argument is needed to check that reflective types and
64     * generic types match.
65     *
66     * @param tclass the class of the objects holding the field
67     * @param fieldName the name of the field to be updated
68     * @return the updater
69     * @throws IllegalArgumentException if the field is not a
70     * volatile integer type
71     * @throws RuntimeException with a nested reflection-based
72     * exception if the class does not hold field or is the wrong type
73     */
74    @CallerSensitive
75    public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
76        return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
77    }
78
79    /**
80     * Protected do-nothing constructor for use by subclasses.
81     */
82    protected AtomicIntegerFieldUpdater() {
83    }
84
85    /**
86     * Atomically sets the field of the given object managed by this updater
87     * to the given updated value if the current value {@code ==} the
88     * expected value. This method is guaranteed to be atomic with respect to
89     * other calls to {@code compareAndSet} and {@code set}, but not
90     * necessarily with respect to other changes in the field.
91     *
92     * @param obj An object whose field to conditionally set
93     * @param expect the expected value
94     * @param update the new value
95     * @return true if successful
96     * @throws ClassCastException if {@code obj} is not an instance
97     * of the class possessing the field established in the constructor
98     */
99    public abstract boolean compareAndSet(T obj, int expect, int update);
100
101    /**
102     * Atomically sets the field of the given object managed by this updater
103     * to the given updated value if the current value {@code ==} the
104     * expected value. This method is guaranteed to be atomic with respect to
105     * other calls to {@code compareAndSet} and {@code set}, but not
106     * necessarily with respect to other changes in the field.
107     *
108     * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
109     * and does not provide ordering guarantees, so is only rarely an
110     * appropriate alternative to {@code compareAndSet}.
111     *
112     * @param obj An object whose field to conditionally set
113     * @param expect the expected value
114     * @param update the new value
115     * @return true if successful
116     * @throws ClassCastException if {@code obj} is not an instance
117     * of the class possessing the field established in the constructor
118     */
119    public abstract boolean weakCompareAndSet(T obj, int expect, int update);
120
121    /**
122     * Sets the field of the given object managed by this updater to the
123     * given updated value. This operation is guaranteed to act as a volatile
124     * store with respect to subsequent invocations of {@code compareAndSet}.
125     *
126     * @param obj An object whose field to set
127     * @param newValue the new value
128     */
129    public abstract void set(T obj, int newValue);
130
131    /**
132     * Eventually sets the field of the given object managed by this
133     * updater to the given updated value.
134     *
135     * @param obj An object whose field to set
136     * @param newValue the new value
137     * @since 1.6
138     */
139    public abstract void lazySet(T obj, int newValue);
140
141
142    /**
143     * Gets the current value held in the field of the given object managed
144     * by this updater.
145     *
146     * @param obj An object whose field to get
147     * @return the current value
148     */
149    public abstract int get(T obj);
150
151    /**
152     * Atomically sets the field of the given object managed by this updater
153     * to the given value and returns the old value.
154     *
155     * @param obj An object whose field to get and set
156     * @param newValue the new value
157     * @return the previous value
158     */
159    public int getAndSet(T obj, int newValue) {
160        for (;;) {
161            int current = get(obj);
162            if (compareAndSet(obj, current, newValue))
163                return current;
164        }
165    }
166
167    /**
168     * Atomically increments by one the current value of the field of the
169     * given object managed by this updater.
170     *
171     * @param obj An object whose field to get and set
172     * @return the previous value
173     */
174    public int getAndIncrement(T obj) {
175        for (;;) {
176            int current = get(obj);
177            int next = current + 1;
178            if (compareAndSet(obj, current, next))
179                return current;
180        }
181    }
182
183    /**
184     * Atomically decrements by one the current value of the field of the
185     * given object managed by this updater.
186     *
187     * @param obj An object whose field to get and set
188     * @return the previous value
189     */
190    public int getAndDecrement(T obj) {
191        for (;;) {
192            int current = get(obj);
193            int next = current - 1;
194            if (compareAndSet(obj, current, next))
195                return current;
196        }
197    }
198
199    /**
200     * Atomically adds the given value to the current value of the field of
201     * the given object managed by this updater.
202     *
203     * @param obj An object whose field to get and set
204     * @param delta the value to add
205     * @return the previous value
206     */
207    public int getAndAdd(T obj, int delta) {
208        for (;;) {
209            int current = get(obj);
210            int next = current + delta;
211            if (compareAndSet(obj, current, next))
212                return current;
213        }
214    }
215
216    /**
217     * Atomically increments by one the current value of the field of the
218     * given object managed by this updater.
219     *
220     * @param obj An object whose field to get and set
221     * @return the updated value
222     */
223    public int incrementAndGet(T obj) {
224        for (;;) {
225            int current = get(obj);
226            int next = current + 1;
227            if (compareAndSet(obj, current, next))
228                return next;
229        }
230    }
231
232    /**
233     * Atomically decrements by one the current value of the field of the
234     * given object managed by this updater.
235     *
236     * @param obj An object whose field to get and set
237     * @return the updated value
238     */
239    public int decrementAndGet(T obj) {
240        for (;;) {
241            int current = get(obj);
242            int next = current - 1;
243            if (compareAndSet(obj, current, next))
244                return next;
245        }
246    }
247
248    /**
249     * Atomically adds the given value to the current value of the field of
250     * the given object managed by this updater.
251     *
252     * @param obj An object whose field to get and set
253     * @param delta the value to add
254     * @return the updated value
255     */
256    public int addAndGet(T obj, int delta) {
257        for (;;) {
258            int current = get(obj);
259            int next = current + delta;
260            if (compareAndSet(obj, current, next))
261                return next;
262        }
263    }
264
265    /**
266     * Standard hotspot implementation using intrinsics
267     */
268    private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T> {
269        private static final Unsafe unsafe = Unsafe.getUnsafe();
270        private final long offset;
271        private final Class<T> tclass;
272        private final Class cclass;
273
274        AtomicIntegerFieldUpdaterImpl(Class<T> tclass, String fieldName, Class<?> caller) {
275            Field field = null;
276            int modifiers = 0;
277            try {
278                field = tclass.getDeclaredField(fieldName);
279                modifiers = field.getModifiers();
280                sun.reflect.misc.ReflectUtil.ensureMemberAccess(
281                    caller, tclass, null, modifiers);
282                sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
283            } catch (Exception ex) {
284                throw new RuntimeException(ex);
285            }
286
287            Class fieldt = field.getType();
288            if (fieldt != int.class)
289                throw new IllegalArgumentException("Must be integer type");
290
291            if (!Modifier.isVolatile(modifiers))
292                throw new IllegalArgumentException("Must be volatile type");
293
294            this.cclass = (Modifier.isProtected(modifiers) &&
295                           caller != tclass) ? caller : null;
296            this.tclass = tclass;
297            offset = unsafe.objectFieldOffset(field);
298        }
299
300        private void fullCheck(T obj) {
301            if (!tclass.isInstance(obj))
302                throw new ClassCastException();
303            if (cclass != null)
304                ensureProtectedAccess(obj);
305        }
306
307        public boolean compareAndSet(T obj, int expect, int update) {
308            if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
309            return unsafe.compareAndSwapInt(obj, offset, expect, update);
310        }
311
312        public boolean weakCompareAndSet(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 void set(T obj, int newValue) {
318            if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
319            unsafe.putIntVolatile(obj, offset, newValue);
320        }
321
322        public void lazySet(T obj, int newValue) {
323            if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
324            unsafe.putOrderedInt(obj, offset, newValue);
325        }
326
327        public final int get(T obj) {
328            if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
329            return unsafe.getIntVolatile(obj, offset);
330        }
331
332        private void ensureProtectedAccess(T obj) {
333            if (cclass.isInstance(obj)) {
334                return;
335            }
336            throw new RuntimeException(
337                new IllegalAccessException("Class " +
338                    cclass.getName() +
339                    " can not access a protected member of class " +
340                    tclass.getName() +
341                    " using an instance of " +
342                    obj.getClass().getName()
343                )
344            );
345        }
346    }
347}
348