ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/jdk7/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
Revision: 1.6
Committed: Sat Jul 20 20:12:37 2013 UTC (10 years, 11 months ago) by jsr166
Branch: MAIN
Changes since 1.5: +2 -0 lines
Log Message:
sync javadoc fixes from src/main

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 import sun.misc.Unsafe;
9 import java.lang.reflect.Field;
10 import java.lang.reflect.Modifier;
11 import java.security.AccessController;
12 import java.security.PrivilegedExceptionAction;
13 import java.security.PrivilegedActionException;
14
15 /**
16 * A reflection-based utility that enables atomic updates to
17 * designated {@code volatile} reference fields of designated
18 * classes. This class is designed for use in atomic data structures
19 * in which several reference fields of the same node are
20 * independently subject to atomic updates. For example, a tree node
21 * might be declared as
22 *
23 * <pre> {@code
24 * class Node {
25 * private volatile Node left, right;
26 *
27 * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
28 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
29 * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
30 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
31 *
32 * Node getLeft() { return left; }
33 * boolean compareAndSetLeft(Node expect, Node update) {
34 * return leftUpdater.compareAndSet(this, expect, update);
35 * }
36 * // ... and so on
37 * }}</pre>
38 *
39 * <p>Note that the guarantees of the {@code compareAndSet}
40 * method in this class are weaker than in other atomic classes.
41 * Because this class cannot ensure that all uses of the field
42 * are appropriate for purposes of atomic access, it can
43 * guarantee atomicity only with respect to other invocations of
44 * {@code compareAndSet} and {@code set} on the same updater.
45 *
46 * @since 1.5
47 * @author Doug Lea
48 * @param <T> The type of the object holding the updatable field
49 * @param <V> The type of the field
50 */
51 public abstract class AtomicReferenceFieldUpdater<T,V> {
52
53 /**
54 * Creates and returns an updater for objects with the given field.
55 * The Class arguments are needed to check that reflective types and
56 * generic types match.
57 *
58 * @param tclass the class of the objects holding the field
59 * @param vclass the class of the field
60 * @param fieldName the name of the field to be updated
61 * @param <U> the type of instances of tclass
62 * @param <W> the type of instances of vclass
63 * @return the updater
64 * @throws IllegalArgumentException if the field is not a volatile reference type
65 * @throws RuntimeException with a nested reflection-based
66 * exception if the class does not hold field or is the wrong type,
67 * or the field is inaccessible to the caller according to Java language
68 * access control
69 */
70 public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
71 return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
72 vclass,
73 fieldName);
74 }
75
76 /**
77 * Protected do-nothing constructor for use by subclasses.
78 */
79 protected AtomicReferenceFieldUpdater() {
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 */
94 public abstract boolean compareAndSet(T obj, V expect, V update);
95
96 /**
97 * Atomically sets the field of the given object managed by this updater
98 * to the given updated value if the current value {@code ==} the
99 * expected value. This method is guaranteed to be atomic with respect to
100 * other calls to {@code compareAndSet} and {@code set}, but not
101 * necessarily with respect to other changes in the field.
102 *
103 * <p><a href="package-summary.html#weakCompareAndSet">May fail
104 * spuriously and does not provide ordering guarantees</a>, so is
105 * only rarely an appropriate alternative to {@code compareAndSet}.
106 *
107 * @param obj An object whose field to conditionally set
108 * @param expect the expected value
109 * @param update the new value
110 * @return true if successful
111 */
112 public abstract boolean weakCompareAndSet(T obj, V expect, V update);
113
114 /**
115 * Sets the field of the given object managed by this updater to the
116 * given updated value. This operation is guaranteed to act as a volatile
117 * store with respect to subsequent invocations of {@code compareAndSet}.
118 *
119 * @param obj An object whose field to set
120 * @param newValue the new value
121 */
122 public abstract void set(T obj, V newValue);
123
124 /**
125 * Eventually sets the field of the given object managed by this
126 * updater to the given updated value.
127 *
128 * @param obj An object whose field to set
129 * @param newValue the new value
130 * @since 1.6
131 */
132 public abstract void lazySet(T obj, V newValue);
133
134 /**
135 * Gets the current value held in the field of the given object managed
136 * by this updater.
137 *
138 * @param obj An object whose field to get
139 * @return the current value
140 */
141 public abstract V get(T obj);
142
143 /**
144 * Atomically sets the field of the given object managed by this updater
145 * to the given value and returns the old value.
146 *
147 * @param obj An object whose field to get and set
148 * @param newValue the new value
149 * @return the previous value
150 */
151 public V getAndSet(T obj, V newValue) {
152 for (;;) {
153 V current = get(obj);
154 if (compareAndSet(obj, current, newValue))
155 return current;
156 }
157 }
158
159 private static final class AtomicReferenceFieldUpdaterImpl<T,V>
160 extends AtomicReferenceFieldUpdater<T,V> {
161 private static final Unsafe unsafe = Unsafe.getUnsafe();
162 private final long offset;
163 private final Class<T> tclass;
164 private final Class<V> vclass;
165 private final Class<?> cclass;
166
167 /*
168 * Internal type checks within all update methods contain
169 * internal inlined optimizations checking for the common
170 * cases where the class is final (in which case a simple
171 * getClass comparison suffices) or is of type Object (in
172 * which case no check is needed because all objects are
173 * instances of Object). The Object case is handled simply by
174 * setting vclass to null in constructor. The targetCheck and
175 * updateCheck methods are invoked when these faster
176 * screenings fail.
177 */
178
179 AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
180 Class<V> vclass,
181 final String fieldName) {
182 final Field field;
183 final Class<?> fieldClass;
184 final Class<?> caller;
185 final int modifiers;
186 try {
187 field = AccessController.doPrivileged(
188 new PrivilegedExceptionAction<Field>() {
189 public Field run() throws NoSuchFieldException {
190 return tclass.getDeclaredField(fieldName);
191 }
192 });
193 caller = sun.reflect.Reflection.getCallerClass(3);
194 modifiers = field.getModifiers();
195 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
196 caller, tclass, null, modifiers);
197 ClassLoader cl = tclass.getClassLoader();
198 ClassLoader ccl = caller.getClassLoader();
199 if ((ccl != null) && (ccl != cl) &&
200 ((cl == null) || !isAncestor(cl, ccl))) {
201 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
202 }
203 fieldClass = field.getType();
204 } catch (PrivilegedActionException pae) {
205 throw new RuntimeException(pae.getException());
206 } catch (Exception ex) {
207 throw new RuntimeException(ex);
208 }
209
210 if (vclass != fieldClass)
211 throw new ClassCastException();
212
213 if (!Modifier.isVolatile(modifiers))
214 throw new IllegalArgumentException("Must be volatile type");
215
216 this.cclass = (Modifier.isProtected(modifiers) &&
217 caller != tclass) ? caller : null;
218 this.tclass = tclass;
219 if (vclass == Object.class)
220 this.vclass = null;
221 else
222 this.vclass = vclass;
223 offset = unsafe.objectFieldOffset(field);
224 }
225
226 /**
227 * Returns true if the second classloader can be found in the first
228 * classloader's delegation chain.
229 * Equivalent to the inaccessible: first.isAncestor(second).
230 */
231 private static boolean isAncestor(ClassLoader first, ClassLoader second) {
232 ClassLoader acl = first;
233 do {
234 acl = acl.getParent();
235 if (second == acl) {
236 return true;
237 }
238 } while (acl != null);
239 return false;
240 }
241
242 void targetCheck(T obj) {
243 if (!tclass.isInstance(obj))
244 throw new ClassCastException();
245 if (cclass != null)
246 ensureProtectedAccess(obj);
247 }
248
249 void updateCheck(T obj, V update) {
250 if (!tclass.isInstance(obj) ||
251 (update != null && vclass != null && !vclass.isInstance(update)))
252 throw new ClassCastException();
253 if (cclass != null)
254 ensureProtectedAccess(obj);
255 }
256
257 public boolean compareAndSet(T obj, V expect, V update) {
258 if (obj == null || obj.getClass() != tclass || cclass != null ||
259 (update != null && vclass != null &&
260 vclass != update.getClass()))
261 updateCheck(obj, update);
262 return unsafe.compareAndSwapObject(obj, offset, expect, update);
263 }
264
265 public boolean weakCompareAndSet(T obj, V expect, V update) {
266 // same implementation as strong form for now
267 if (obj == null || obj.getClass() != tclass || cclass != null ||
268 (update != null && vclass != null &&
269 vclass != update.getClass()))
270 updateCheck(obj, update);
271 return unsafe.compareAndSwapObject(obj, offset, expect, update);
272 }
273
274 public void set(T obj, V newValue) {
275 if (obj == null || obj.getClass() != tclass || cclass != null ||
276 (newValue != null && vclass != null &&
277 vclass != newValue.getClass()))
278 updateCheck(obj, newValue);
279 unsafe.putObjectVolatile(obj, offset, newValue);
280 }
281
282 public void lazySet(T obj, V newValue) {
283 if (obj == null || obj.getClass() != tclass || cclass != null ||
284 (newValue != null && vclass != null &&
285 vclass != newValue.getClass()))
286 updateCheck(obj, newValue);
287 unsafe.putOrderedObject(obj, offset, newValue);
288 }
289
290 @SuppressWarnings("unchecked")
291 public V get(T obj) {
292 if (obj == null || obj.getClass() != tclass || cclass != null)
293 targetCheck(obj);
294 return (V)unsafe.getObjectVolatile(obj, offset);
295 }
296
297 private void ensureProtectedAccess(T obj) {
298 if (cclass.isInstance(obj)) {
299 return;
300 }
301 throw new RuntimeException(
302 new IllegalAccessException("Class " +
303 cclass.getName() +
304 " can not access a protected member of class " +
305 tclass.getName() +
306 " using an instance of " +
307 obj.getClass().getName()
308 )
309 );
310 }
311 }
312 }