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.8
Committed: Fri Sep 27 17:07:44 2013 UTC (10 years, 9 months ago) by jsr166
Branch: MAIN
Changes since 1.7: +5 -4 lines
Log Message:
No spaces separating one-character type parameters

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,
71 Class<W> vclass,
72 String fieldName) {
73 return new AtomicReferenceFieldUpdaterImpl<U,W>
74 (tclass, vclass, fieldName);
75 }
76
77 /**
78 * Protected do-nothing constructor for use by subclasses.
79 */
80 protected AtomicReferenceFieldUpdater() {
81 }
82
83 /**
84 * Atomically sets the field of the given object managed by this updater
85 * to the given updated value if the current value {@code ==} the
86 * expected value. This method is guaranteed to be atomic with respect to
87 * other calls to {@code compareAndSet} and {@code set}, but not
88 * necessarily with respect to other changes in the field.
89 *
90 * @param obj An object whose field to conditionally set
91 * @param expect the expected value
92 * @param update the new value
93 * @return true if successful
94 */
95 public abstract boolean compareAndSet(T obj, V expect, V update);
96
97 /**
98 * Atomically sets the field of the given object managed by this updater
99 * to the given updated value if the current value {@code ==} the
100 * expected value. This method is guaranteed to be atomic with respect to
101 * other calls to {@code compareAndSet} and {@code set}, but not
102 * necessarily with respect to other changes in the field.
103 *
104 * <p><a href="package-summary.html#weakCompareAndSet">May fail
105 * spuriously and does not provide ordering guarantees</a>, so is
106 * only rarely an appropriate alternative to {@code compareAndSet}.
107 *
108 * @param obj An object whose field to conditionally set
109 * @param expect the expected value
110 * @param update the new value
111 * @return true if successful
112 */
113 public abstract boolean weakCompareAndSet(T obj, V expect, V update);
114
115 /**
116 * Sets the field of the given object managed by this updater to the
117 * given updated value. This operation is guaranteed to act as a volatile
118 * store with respect to subsequent invocations of {@code compareAndSet}.
119 *
120 * @param obj An object whose field to set
121 * @param newValue the new value
122 */
123 public abstract void set(T obj, V newValue);
124
125 /**
126 * Eventually sets the field of the given object managed by this
127 * updater to the given updated value.
128 *
129 * @param obj An object whose field to set
130 * @param newValue the new value
131 * @since 1.6
132 */
133 public abstract void lazySet(T obj, V newValue);
134
135 /**
136 * Gets the current value held in the field of the given object managed
137 * by this updater.
138 *
139 * @param obj An object whose field to get
140 * @return the current value
141 */
142 public abstract V get(T obj);
143
144 /**
145 * Atomically sets the field of the given object managed by this updater
146 * to the given value and returns the old value.
147 *
148 * @param obj An object whose field to get and set
149 * @param newValue the new value
150 * @return the previous value
151 */
152 public V getAndSet(T obj, V newValue) {
153 for (;;) {
154 V current = get(obj);
155 if (compareAndSet(obj, current, newValue))
156 return current;
157 }
158 }
159
160 private static final class AtomicReferenceFieldUpdaterImpl<T,V>
161 extends AtomicReferenceFieldUpdater<T,V> {
162 private static final Unsafe unsafe = Unsafe.getUnsafe();
163 private final long offset;
164 private final Class<T> tclass;
165 private final Class<V> vclass;
166 private final Class<?> cclass;
167
168 /*
169 * Internal type checks within all update methods contain
170 * internal inlined optimizations checking for the common
171 * cases where the class is final (in which case a simple
172 * getClass comparison suffices) or is of type Object (in
173 * which case no check is needed because all objects are
174 * instances of Object). The Object case is handled simply by
175 * setting vclass to null in constructor. The targetCheck and
176 * updateCheck methods are invoked when these faster
177 * screenings fail.
178 */
179
180 AtomicReferenceFieldUpdaterImpl(final Class<T> tclass,
181 Class<V> vclass,
182 final String fieldName) {
183 final Field field;
184 final Class<?> fieldClass;
185 final Class<?> caller;
186 final int modifiers;
187 try {
188 field = AccessController.doPrivileged(
189 new PrivilegedExceptionAction<Field>() {
190 public Field run() throws NoSuchFieldException {
191 return tclass.getDeclaredField(fieldName);
192 }
193 });
194 caller = sun.reflect.Reflection.getCallerClass(3);
195 modifiers = field.getModifiers();
196 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
197 caller, tclass, null, modifiers);
198 ClassLoader cl = tclass.getClassLoader();
199 ClassLoader ccl = caller.getClassLoader();
200 if ((ccl != null) && (ccl != cl) &&
201 ((cl == null) || !isAncestor(cl, ccl))) {
202 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
203 }
204 fieldClass = field.getType();
205 } catch (PrivilegedActionException pae) {
206 throw new RuntimeException(pae.getException());
207 } catch (Exception ex) {
208 throw new RuntimeException(ex);
209 }
210
211 if (vclass != fieldClass)
212 throw new ClassCastException();
213
214 if (!Modifier.isVolatile(modifiers))
215 throw new IllegalArgumentException("Must be volatile type");
216
217 this.cclass = (Modifier.isProtected(modifiers) &&
218 caller != tclass) ? caller : null;
219 this.tclass = tclass;
220 if (vclass == Object.class)
221 this.vclass = null;
222 else
223 this.vclass = vclass;
224 offset = unsafe.objectFieldOffset(field);
225 }
226
227 /**
228 * Returns true if the second classloader can be found in the first
229 * classloader's delegation chain.
230 * Equivalent to the inaccessible: first.isAncestor(second).
231 */
232 private static boolean isAncestor(ClassLoader first, ClassLoader second) {
233 ClassLoader acl = first;
234 do {
235 acl = acl.getParent();
236 if (second == acl) {
237 return true;
238 }
239 } while (acl != null);
240 return false;
241 }
242
243 void targetCheck(T obj) {
244 if (!tclass.isInstance(obj))
245 throw new ClassCastException();
246 if (cclass != null)
247 ensureProtectedAccess(obj);
248 }
249
250 void updateCheck(T obj, V update) {
251 if (!tclass.isInstance(obj) ||
252 (update != null && vclass != null && !vclass.isInstance(update)))
253 throw new ClassCastException();
254 if (cclass != null)
255 ensureProtectedAccess(obj);
256 }
257
258 public boolean compareAndSet(T obj, V expect, V update) {
259 if (obj == null || obj.getClass() != tclass || cclass != null ||
260 (update != null && vclass != null &&
261 vclass != update.getClass()))
262 updateCheck(obj, update);
263 return unsafe.compareAndSwapObject(obj, offset, expect, update);
264 }
265
266 public boolean weakCompareAndSet(T obj, V expect, V update) {
267 // same implementation as strong form for now
268 if (obj == null || obj.getClass() != tclass || cclass != null ||
269 (update != null && vclass != null &&
270 vclass != update.getClass()))
271 updateCheck(obj, update);
272 return unsafe.compareAndSwapObject(obj, offset, expect, update);
273 }
274
275 public void set(T obj, V newValue) {
276 if (obj == null || obj.getClass() != tclass || cclass != null ||
277 (newValue != null && vclass != null &&
278 vclass != newValue.getClass()))
279 updateCheck(obj, newValue);
280 unsafe.putObjectVolatile(obj, offset, newValue);
281 }
282
283 public void lazySet(T obj, V newValue) {
284 if (obj == null || obj.getClass() != tclass || cclass != null ||
285 (newValue != null && vclass != null &&
286 vclass != newValue.getClass()))
287 updateCheck(obj, newValue);
288 unsafe.putOrderedObject(obj, offset, newValue);
289 }
290
291 @SuppressWarnings("unchecked")
292 public V get(T obj) {
293 if (obj == null || obj.getClass() != tclass || cclass != null)
294 targetCheck(obj);
295 return (V)unsafe.getObjectVolatile(obj, offset);
296 }
297
298 private void ensureProtectedAccess(T obj) {
299 if (cclass.isInstance(obj)) {
300 return;
301 }
302 throw new RuntimeException(
303 new IllegalAccessException("Class " +
304 cclass.getName() +
305 " can not access a protected member of class " +
306 tclass.getName() +
307 " using an instance of " +
308 obj.getClass().getName()
309 )
310 );
311 }
312 }
313 }