Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
+++ new/src/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
1 1 /*
2 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3 3 *
4 4 * This code is free software; you can redistribute it and/or modify it
5 5 * under the terms of the GNU General Public License version 2 only, as
6 6 * published by the Free Software Foundation. Oracle designates this
7 7 * particular file as subject to the "Classpath" exception as provided
8 8 * by Oracle in the LICENSE file that accompanied this code.
9 9 *
10 10 * This code is distributed in the hope that it will be useful, but WITHOUT
11 11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 13 * version 2 for more details (a copy is included in the LICENSE file that
14 14 * accompanied this code).
15 15 *
16 16 * You should have received a copy of the GNU General Public License version
17 17 * 2 along with this work; if not, write to the Free Software Foundation,
18 18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19 19 *
20 20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
21 21 * or visit www.oracle.com if you need additional information or have any
22 22 * questions.
23 23 */
24 24
25 25 /*
26 26 * This file is available under and governed by the GNU General Public
27 27 * License version 2 only, as published by the Free Software Foundation.
28 28 * However, the following notice accompanied the original version of this
29 29 * file:
30 30 *
31 31 * Written by Doug Lea with assistance from members of JCP JSR-166
32 32 * Expert Group and released to the public domain, as explained at
33 33 * http://creativecommons.org/licenses/publicdomain
34 34 */
35 35
36 36 package java.util.concurrent.atomic;
37 37 import sun.misc.Unsafe;
↓ open down ↓ |
37 lines elided |
↑ open up ↑ |
38 38 import java.lang.reflect.*;
39 39
40 40 /**
41 41 * A reflection-based utility that enables atomic updates to
42 42 * designated {@code volatile} reference fields of designated
43 43 * classes. This class is designed for use in atomic data structures
44 44 * in which several reference fields of the same node are
45 45 * independently subject to atomic updates. For example, a tree node
46 46 * might be declared as
47 47 *
48 - * <pre>
48 + * <pre> {@code
49 49 * class Node {
50 50 * private volatile Node left, right;
51 51 *
52 - * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
52 + * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
53 53 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
54 - * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
54 + * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
55 55 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
56 56 *
57 57 * Node getLeft() { return left; }
58 58 * boolean compareAndSetLeft(Node expect, Node update) {
59 59 * return leftUpdater.compareAndSet(this, expect, update);
60 60 * }
61 61 * // ... and so on
62 - * }
63 - * </pre>
62 + * }}</pre>
64 63 *
65 64 * <p>Note that the guarantees of the {@code compareAndSet}
66 65 * method in this class are weaker than in other atomic classes.
67 66 * Because this class cannot ensure that all uses of the field
68 67 * are appropriate for purposes of atomic access, it can
69 68 * guarantee atomicity only with respect to other invocations of
70 69 * {@code compareAndSet} and {@code set} on the same updater.
71 70 *
72 71 * @since 1.5
73 72 * @author Doug Lea
74 73 * @param <T> The type of the object holding the updatable field
75 74 * @param <V> The type of the field
76 75 */
77 -public abstract class AtomicReferenceFieldUpdater<T, V> {
76 +public abstract class AtomicReferenceFieldUpdater<T, V> {
78 77
79 78 /**
80 79 * Creates and returns an updater for objects with the given field.
81 80 * The Class arguments are needed to check that reflective types and
82 81 * generic types match.
83 82 *
84 83 * @param tclass the class of the objects holding the field.
85 84 * @param vclass the class of the field
86 85 * @param fieldName the name of the field to be updated.
87 86 * @return the updater
88 87 * @throws IllegalArgumentException if the field is not a volatile reference type.
89 88 * @throws RuntimeException with a nested reflection-based
90 89 * exception if the class does not hold field or is the wrong type.
91 90 */
92 91 public static <U, W> AtomicReferenceFieldUpdater<U,W> newUpdater(Class<U> tclass, Class<W> vclass, String fieldName) {
93 92 return new AtomicReferenceFieldUpdaterImpl<U,W>(tclass,
94 93 vclass,
95 94 fieldName);
96 95 }
97 96
98 97 /**
99 98 * Protected do-nothing constructor for use by subclasses.
100 99 */
101 100 protected AtomicReferenceFieldUpdater() {
102 101 }
103 102
104 103 /**
105 104 * Atomically sets the field of the given object managed by this updater
106 105 * to the given updated value if the current value {@code ==} the
107 106 * expected value. This method is guaranteed to be atomic with respect to
108 107 * other calls to {@code compareAndSet} and {@code set}, but not
109 108 * necessarily with respect to other changes in the field.
110 109 *
111 110 * @param obj An object whose field to conditionally set
112 111 * @param expect the expected value
113 112 * @param update the new value
114 113 * @return true if successful.
115 114 */
116 115 public abstract boolean compareAndSet(T obj, V expect, V update);
117 116
118 117 /**
119 118 * Atomically sets the field of the given object managed by this updater
120 119 * to the given updated value if the current value {@code ==} the
121 120 * expected value. This method is guaranteed to be atomic with respect to
122 121 * other calls to {@code compareAndSet} and {@code set}, but not
123 122 * necessarily with respect to other changes in the field.
124 123 *
125 124 * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
126 125 * and does not provide ordering guarantees, so is only rarely an
127 126 * appropriate alternative to {@code compareAndSet}.
128 127 *
129 128 * @param obj An object whose field to conditionally set
130 129 * @param expect the expected value
131 130 * @param update the new value
132 131 * @return true if successful.
133 132 */
134 133 public abstract boolean weakCompareAndSet(T obj, V expect, V update);
135 134
136 135 /**
137 136 * Sets the field of the given object managed by this updater to the
138 137 * given updated value. This operation is guaranteed to act as a volatile
139 138 * store with respect to subsequent invocations of {@code compareAndSet}.
140 139 *
141 140 * @param obj An object whose field to set
142 141 * @param newValue the new value
143 142 */
144 143 public abstract void set(T obj, V newValue);
145 144
146 145 /**
147 146 * Eventually sets the field of the given object managed by this
148 147 * updater to the given updated value.
149 148 *
150 149 * @param obj An object whose field to set
151 150 * @param newValue the new value
152 151 * @since 1.6
153 152 */
154 153 public abstract void lazySet(T obj, V newValue);
155 154
156 155 /**
157 156 * Gets the current value held in the field of the given object managed
158 157 * by this updater.
159 158 *
160 159 * @param obj An object whose field to get
161 160 * @return the current value
162 161 */
163 162 public abstract V get(T obj);
164 163
165 164 /**
166 165 * Atomically sets the field of the given object managed by this updater
167 166 * to the given value and returns the old value.
168 167 *
169 168 * @param obj An object whose field to get and set
170 169 * @param newValue the new value
171 170 * @return the previous value
172 171 */
173 172 public V getAndSet(T obj, V newValue) {
174 173 for (;;) {
175 174 V current = get(obj);
176 175 if (compareAndSet(obj, current, newValue))
177 176 return current;
178 177 }
179 178 }
180 179
181 180 private static final class AtomicReferenceFieldUpdaterImpl<T,V>
182 181 extends AtomicReferenceFieldUpdater<T,V> {
183 182 private static final Unsafe unsafe = Unsafe.getUnsafe();
184 183 private final long offset;
185 184 private final Class<T> tclass;
186 185 private final Class<V> vclass;
187 186 private final Class cclass;
188 187
189 188 /*
190 189 * Internal type checks within all update methods contain
191 190 * internal inlined optimizations checking for the common
192 191 * cases where the class is final (in which case a simple
193 192 * getClass comparison suffices) or is of type Object (in
194 193 * which case no check is needed because all objects are
195 194 * instances of Object). The Object case is handled simply by
196 195 * setting vclass to null in constructor. The targetCheck and
197 196 * updateCheck methods are invoked when these faster
198 197 * screenings fail.
199 198 */
200 199
201 200 AtomicReferenceFieldUpdaterImpl(Class<T> tclass,
202 201 Class<V> vclass,
203 202 String fieldName) {
204 203 Field field = null;
205 204 Class fieldClass = null;
206 205 Class caller = null;
207 206 int modifiers = 0;
208 207 try {
209 208 field = tclass.getDeclaredField(fieldName);
210 209 caller = sun.reflect.Reflection.getCallerClass(3);
211 210 modifiers = field.getModifiers();
212 211 sun.reflect.misc.ReflectUtil.ensureMemberAccess(
213 212 caller, tclass, null, modifiers);
214 213 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
215 214 fieldClass = field.getType();
216 215 } catch (Exception ex) {
217 216 throw new RuntimeException(ex);
218 217 }
219 218
220 219 if (vclass != fieldClass)
221 220 throw new ClassCastException();
222 221
223 222 if (!Modifier.isVolatile(modifiers))
224 223 throw new IllegalArgumentException("Must be volatile type");
225 224
226 225 this.cclass = (Modifier.isProtected(modifiers) &&
227 226 caller != tclass) ? caller : null;
228 227 this.tclass = tclass;
229 228 if (vclass == Object.class)
230 229 this.vclass = null;
231 230 else
232 231 this.vclass = vclass;
233 232 offset = unsafe.objectFieldOffset(field);
234 233 }
235 234
236 235 void targetCheck(T obj) {
237 236 if (!tclass.isInstance(obj))
238 237 throw new ClassCastException();
239 238 if (cclass != null)
240 239 ensureProtectedAccess(obj);
241 240 }
242 241
243 242 void updateCheck(T obj, V update) {
244 243 if (!tclass.isInstance(obj) ||
245 244 (update != null && vclass != null && !vclass.isInstance(update)))
246 245 throw new ClassCastException();
247 246 if (cclass != null)
248 247 ensureProtectedAccess(obj);
249 248 }
250 249
251 250 public boolean compareAndSet(T obj, V expect, V update) {
252 251 if (obj == null || obj.getClass() != tclass || cclass != null ||
253 252 (update != null && vclass != null &&
254 253 vclass != update.getClass()))
255 254 updateCheck(obj, update);
256 255 return unsafe.compareAndSwapObject(obj, offset, expect, update);
257 256 }
258 257
259 258 public boolean weakCompareAndSet(T obj, V expect, V update) {
260 259 // same implementation as strong form for now
261 260 if (obj == null || obj.getClass() != tclass || cclass != null ||
262 261 (update != null && vclass != null &&
263 262 vclass != update.getClass()))
264 263 updateCheck(obj, update);
265 264 return unsafe.compareAndSwapObject(obj, offset, expect, update);
266 265 }
267 266
268 267 public void set(T obj, V newValue) {
269 268 if (obj == null || obj.getClass() != tclass || cclass != null ||
270 269 (newValue != null && vclass != null &&
271 270 vclass != newValue.getClass()))
272 271 updateCheck(obj, newValue);
273 272 unsafe.putObjectVolatile(obj, offset, newValue);
274 273 }
275 274
276 275 public void lazySet(T obj, V newValue) {
277 276 if (obj == null || obj.getClass() != tclass || cclass != null ||
278 277 (newValue != null && vclass != null &&
279 278 vclass != newValue.getClass()))
280 279 updateCheck(obj, newValue);
281 280 unsafe.putOrderedObject(obj, offset, newValue);
282 281 }
283 282
↓ open down ↓ |
196 lines elided |
↑ open up ↑ |
284 283 public V get(T obj) {
285 284 if (obj == null || obj.getClass() != tclass || cclass != null)
286 285 targetCheck(obj);
287 286 return (V)unsafe.getObjectVolatile(obj, offset);
288 287 }
289 288
290 289 private void ensureProtectedAccess(T obj) {
291 290 if (cclass.isInstance(obj)) {
292 291 return;
293 292 }
294 - throw new RuntimeException (
293 + throw new RuntimeException(
295 294 new IllegalAccessException("Class " +
296 295 cclass.getName() +
297 296 " can not access a protected member of class " +
298 297 tclass.getName() +
299 298 " using an instance of " +
300 299 obj.getClass().getName()
301 300 )
302 301 );
303 302 }
304 303 }
305 304 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX