001 /*
002 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
003 *
004 * This code is free software; you can redistribute it and/or modify it
005 * under the terms of the GNU General Public License version 2 only, as
006 * published by the Free Software Foundation. Sun designates this
007 * particular file as subject to the "Classpath" exception as provided
008 * by Sun in the LICENSE file that accompanied this code.
009 *
010 * This code is distributed in the hope that it will be useful, but WITHOUT
011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
013 * version 2 for more details (a copy is included in the LICENSE file that
014 * accompanied this code).
015 *
016 * You should have received a copy of the GNU General Public License version
017 * 2 along with this work; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
019 *
020 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
021 * CA 95054 USA or visit www.sun.com if you need additional information or
022 * have any questions.
023 */
024
025 /*
026 * This file is available under and governed by the GNU General Public
027 * License version 2 only, as published by the Free Software Foundation.
028 * However, the following notice accompanied the original version of this
029 * file:
030 *
031 * Written by Doug Lea with assistance from members of JCP JSR-166
032 * Expert Group and released to the public domain, as explained at
033 * http://creativecommons.org/licenses/publicdomain
034 */
035
036 package java.util.concurrent.atomic;
037
038 import sun.misc.Unsafe;
039 import java.lang.reflect.*;
040
041 /**
042 * A reflection-based utility that enables atomic updates to
043 * designated {@code volatile} reference fields of designated
044 * classes. This class is designed for use in atomic data structures
045 * in which several reference fields of the same node are
046 * independently subject to atomic updates. For example, a tree node
047 * might be declared as
048 *
049 * <pre>
050 * class Node {
051 * private volatile Node left, right;
052 *
053 * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
054 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
055 * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
056 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
057 *
058 * Node getLeft() { return left; }
059 * boolean compareAndSetLeft(Node expect, Node update) {
060 * return leftUpdater.compareAndSet(this, expect, update);
061 * }
062 * // ... and so on
063 * }
064 * </pre>
065 *
066 * <p>Note that the guarantees of the {@code compareAndSet}
067 * method in this class are weaker than in other atomic classes.
068 * Because this class cannot ensure that all uses of the field
069 * are appropriate for purposes of atomic access, it can
070 * guarantee atomicity only with respect to other invocations of
071 * {@code compareAndSet} and {@code set} on the same updater.
072 *
073 * @since 1.5
074 * @author Doug Lea
075 * @param <T> The type of the object holding the updatable field
076 * @param <V> The type of the field
077 */
078 public abstract class AtomicReferenceFieldUpdater<T, V> {
079
080 /**
081 * Creates and returns an updater for objects with the given field.
082 * The Class arguments are needed to check that reflective types and
083 * generic types match.
084 *
085 * @param tclass the class of the objects holding the field.
086 * @param vclass the class of the field
087 * @param fieldName the name of the field to be updated.
088 * @return the updater
089 * @throws IllegalArgumentException if the field is not a volatile reference type.
090 * @throws RuntimeException with a nested reflection-based
091 * exception if the class does not hold field or is the wrong type.
092 */
093 public static <U, W> AtomicReferenceFieldUpdater<U, W> newUpdater(
094 Class<U> tclass, Class<W> vclass, String fieldName) {
095 return new AtomicReferenceFieldUpdaterImpl<U, W>(tclass,
096 vclass, fieldName);
097 }
098
099 /**
100 * Protected do-nothing constructor for use by subclasses.
101 */
102 protected AtomicReferenceFieldUpdater() {
103 }
104
105 /**
106 * Atomically sets the field of the given object managed by this updater
107 * to the given updated value if the current value {@code ==} the
108 * expected value. This method is guaranteed to be atomic with respect to
109 * other calls to {@code compareAndSet} and {@code set}, but not
110 * necessarily with respect to other changes in the field.
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 */
117 public abstract boolean compareAndSet(T obj, V expect, V update);
118
119 /**
120 * Atomically sets the field of the given object managed by this updater
121 * to the given updated value if the current value {@code ==} the
122 * expected value. This method is guaranteed to be atomic with respect to
123 * other calls to {@code compareAndSet} and {@code set}, but not
124 * necessarily with respect to other changes in the field.
125 *
126 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
127 * and does not provide ordering guarantees, so is only rarely an
128 * appropriate alternative to {@code compareAndSet}.
129 *
130 * @param obj An object whose field to conditionally set
131 * @param expect the expected value
132 * @param update the new value
133 * @return true if successful.
134 */
135 public abstract boolean weakCompareAndSet(T obj, V expect, V update);
136
137 /**
138 * Sets the field of the given object managed by this updater to the
139 * given updated value. This operation is guaranteed to act as a volatile
140 * store with respect to subsequent invocations of {@code compareAndSet}.
141 *
142 * @param obj An object whose field to set
143 * @param newValue the new value
144 */
145 public abstract void set(T obj, V newValue);
146
147 /**
148 * Eventually sets the field of the given object managed by this
149 * updater to the given updated value.
150 *
151 * @param obj An object whose field to set
152 * @param newValue the new value
153 * @since 1.6
154 */
155 public abstract void lazySet(T obj, V newValue);
156
157 /**
158 * Gets the current value held in the field of the given object managed
159 * by this updater.
160 *
161 * @param obj An object whose field to get
162 * @return the current value
163 */
164 public abstract V get(T obj);
165
166 /**
167 * Atomically sets the field of the given object managed by this updater
168 * to the given value and returns the old value.
169 *
170 * @param obj An object whose field to get and set
171 * @param newValue the new value
172 * @return the previous value
173 */
174 public V getAndSet(T obj, V newValue) {
175 for (;;) {
176 V current = get(obj);
177 if (compareAndSet(obj, current, newValue))
178 return current;
179 }
180 }
181
182 private static final class AtomicReferenceFieldUpdaterImpl<T, V>
183 extends AtomicReferenceFieldUpdater<T, V> {
184 private static final Unsafe unsafe = Unsafe.getUnsafe();
185 private final long offset;
186 private final Class<T> tclass;
187 private final Class<V> vclass;
188 private final Class cclass;
189
190 /*
191 * Internal type checks within all update methods contain
192 * internal inlined optimizations checking for the common
193 * cases where the class is final (in which case a simple
194 * getClass comparison suffices) or is of type Object (in
195 * which case no check is needed because all objects are
196 * instances of Object). The Object case is handled simply by
197 * setting vclass to null in constructor. The targetCheck and
198 * updateCheck methods are invoked when these faster
199 * screenings fail.
200 */
201
202 AtomicReferenceFieldUpdaterImpl(Class<T> tclass,
203 Class<V> vclass, String fieldName) {
204 Field field = null;
205 Class fieldClass = null;
206 Class caller = null;
207 int modifiers = 0;
208 try {
209 field = tclass.getDeclaredField(fieldName);
210 caller = sun.reflect.Reflection.getCallerClass(3);
211 modifiers = field.getModifiers();
212 sun.reflect.misc.ReflectUtil.ensureMemberAccess(caller,
213 tclass, null, modifiers);
214 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
215 fieldClass = field.getType();
216 } catch (Exception ex) {
217 throw new RuntimeException(ex);
218 }
219
220 if (vclass != fieldClass)
221 throw new ClassCastException();
222
223 if (!Modifier.isVolatile(modifiers))
224 throw new IllegalArgumentException(
225 "Must be volatile type");
226
227 this .cclass = (Modifier.isProtected(modifiers) && caller != tclass) ? caller
228 : null;
229 this .tclass = tclass;
230 if (vclass == Object.class)
231 this .vclass = null;
232 else
233 this .vclass = vclass;
234 offset = unsafe.objectFieldOffset(field);
235 }
236
237 void targetCheck(T obj) {
238 if (!tclass.isInstance(obj))
239 throw new ClassCastException();
240 if (cclass != null)
241 ensureProtectedAccess(obj);
242 }
243
244 void updateCheck(T obj, V update) {
245 if (!tclass.isInstance(obj)
246 || (update != null && vclass != null && !vclass
247 .isInstance(update)))
248 throw new ClassCastException();
249 if (cclass != null)
250 ensureProtectedAccess(obj);
251 }
252
253 public boolean compareAndSet(T obj, V expect, V update) {
254 if (obj == null
255 || obj.getClass() != tclass
256 || cclass != null
257 || (update != null && vclass != null && vclass != update
258 .getClass()))
259 updateCheck(obj, update);
260 return unsafe.compareAndSwapObject(obj, offset, expect,
261 update);
262 }
263
264 public boolean weakCompareAndSet(T obj, V expect, V update) {
265 // same implementation as strong form for now
266 if (obj == null
267 || obj.getClass() != tclass
268 || cclass != null
269 || (update != null && vclass != null && vclass != update
270 .getClass()))
271 updateCheck(obj, update);
272 return unsafe.compareAndSwapObject(obj, offset, expect,
273 update);
274 }
275
276 public void set(T obj, V newValue) {
277 if (obj == null
278 || obj.getClass() != tclass
279 || cclass != null
280 || (newValue != null && vclass != null && vclass != newValue
281 .getClass()))
282 updateCheck(obj, newValue);
283 unsafe.putObjectVolatile(obj, offset, newValue);
284 }
285
286 public void lazySet(T obj, V newValue) {
287 if (obj == null
288 || obj.getClass() != tclass
289 || cclass != null
290 || (newValue != null && vclass != null && vclass != newValue
291 .getClass()))
292 updateCheck(obj, newValue);
293 unsafe.putOrderedObject(obj, offset, newValue);
294 }
295
296 public V get(T obj) {
297 if (obj == null || obj.getClass() != tclass
298 || cclass != null)
299 targetCheck(obj);
300 return (V) unsafe.getObjectVolatile(obj, offset);
301 }
302
303 private void ensureProtectedAccess(T obj) {
304 if (cclass.isInstance(obj)) {
305 return;
306 }
307 throw new RuntimeException(
308 new IllegalAccessException(
309 "Class "
310 + cclass.getName()
311 + " can not access a protected member of class "
312 + tclass.getName()
313 + " using an instance of "
314 + obj.getClass().getName()));
315 }
316 }
317 }
|