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.2
Committed: Wed Jan 2 06:29:00 2013 UTC (11 years, 5 months ago) by jsr166
Branch: MAIN
Changes since 1.1: +2 -2 lines
Log Message:
@return javadoc style

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