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.9
Committed: Sun Jan 18 20:17:32 2015 UTC (9 years, 4 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.8: +1 -0 lines
Log Message:
exactly one blank line before and after package statements

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