32 * Expert Group and released to the public domain, as explained at |
32 * Expert Group and released to the public domain, as explained at |
33 * http://creativecommons.org/publicdomain/zero/1.0/ |
33 * http://creativecommons.org/publicdomain/zero/1.0/ |
34 */ |
34 */ |
35 |
35 |
36 package java.util.concurrent.atomic; |
36 package java.util.concurrent.atomic; |
37 import java.util.function.UnaryOperator; |
37 |
38 import java.util.function.BinaryOperator; |
|
39 import sun.misc.Unsafe; |
|
40 import java.lang.reflect.Field; |
38 import java.lang.reflect.Field; |
41 import java.lang.reflect.Modifier; |
39 import java.lang.reflect.Modifier; |
42 import java.security.AccessController; |
40 import java.security.AccessController; |
|
41 import java.security.PrivilegedActionException; |
43 import java.security.PrivilegedExceptionAction; |
42 import java.security.PrivilegedExceptionAction; |
44 import java.security.PrivilegedActionException; |
43 import java.util.function.BinaryOperator; |
|
44 import java.util.function.UnaryOperator; |
45 import sun.reflect.CallerSensitive; |
45 import sun.reflect.CallerSensitive; |
46 import sun.reflect.Reflection; |
46 import sun.reflect.Reflection; |
47 |
47 |
48 /** |
48 /** |
49 * A reflection-based utility that enables atomic updates to |
49 * A reflection-based utility that enables atomic updates to |
51 * classes. This class is designed for use in atomic data structures |
51 * classes. This class is designed for use in atomic data structures |
52 * in which several reference fields of the same node are |
52 * in which several reference fields of the same node are |
53 * independently subject to atomic updates. For example, a tree node |
53 * independently subject to atomic updates. For example, a tree node |
54 * might be declared as |
54 * might be declared as |
55 * |
55 * |
56 * <pre> {@code |
56 * <pre> {@code |
57 * class Node { |
57 * class Node { |
58 * private volatile Node left, right; |
58 * private volatile Node left, right; |
59 * |
59 * |
60 * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = |
60 * private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater = |
61 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); |
61 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left"); |
62 * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = |
62 * private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater = |
63 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); |
63 * AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right"); |
64 * |
64 * |
65 * Node getLeft() { return left; } |
65 * Node getLeft() { return left; } |
66 * boolean compareAndSetLeft(Node expect, Node update) { |
66 * boolean compareAndSetLeft(Node expect, Node update) { |
67 * return leftUpdater.compareAndSet(this, expect, update); |
67 * return leftUpdater.compareAndSet(this, expect, update); |
68 * } |
68 * } |
69 * // ... and so on |
69 * // ... and so on |
70 * }}</pre> |
70 * }}</pre> |
321 caller, tclass, null, modifiers); |
321 caller, tclass, null, modifiers); |
322 ClassLoader cl = tclass.getClassLoader(); |
322 ClassLoader cl = tclass.getClassLoader(); |
323 ClassLoader ccl = caller.getClassLoader(); |
323 ClassLoader ccl = caller.getClassLoader(); |
324 if ((ccl != null) && (ccl != cl) && |
324 if ((ccl != null) && (ccl != cl) && |
325 ((cl == null) || !isAncestor(cl, ccl))) { |
325 ((cl == null) || !isAncestor(cl, ccl))) { |
326 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); |
326 sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); |
327 } |
327 } |
328 fieldClass = field.getType(); |
328 fieldClass = field.getType(); |
329 } catch (PrivilegedActionException pae) { |
329 } catch (PrivilegedActionException pae) { |
330 throw new RuntimeException(pae.getException()); |
330 throw new RuntimeException(pae.getException()); |
331 } catch (Exception ex) { |
331 } catch (Exception ex) { |
384 public boolean compareAndSet(T obj, V expect, V update) { |
384 public boolean compareAndSet(T obj, V expect, V update) { |
385 if (obj == null || obj.getClass() != tclass || cclass != null || |
385 if (obj == null || obj.getClass() != tclass || cclass != null || |
386 (update != null && vclass != null && |
386 (update != null && vclass != null && |
387 vclass != update.getClass())) |
387 vclass != update.getClass())) |
388 updateCheck(obj, update); |
388 updateCheck(obj, update); |
389 return unsafe.compareAndSwapObject(obj, offset, expect, update); |
389 return U.compareAndSwapObject(obj, offset, expect, update); |
390 } |
390 } |
391 |
391 |
392 public boolean weakCompareAndSet(T obj, V expect, V update) { |
392 public boolean weakCompareAndSet(T obj, V expect, V update) { |
393 // same implementation as strong form for now |
393 // same implementation as strong form for now |
394 if (obj == null || obj.getClass() != tclass || cclass != null || |
394 if (obj == null || obj.getClass() != tclass || cclass != null || |
395 (update != null && vclass != null && |
395 (update != null && vclass != null && |
396 vclass != update.getClass())) |
396 vclass != update.getClass())) |
397 updateCheck(obj, update); |
397 updateCheck(obj, update); |
398 return unsafe.compareAndSwapObject(obj, offset, expect, update); |
398 return U.compareAndSwapObject(obj, offset, expect, update); |
399 } |
399 } |
400 |
400 |
401 public void set(T obj, V newValue) { |
401 public void set(T obj, V newValue) { |
402 if (obj == null || obj.getClass() != tclass || cclass != null || |
402 if (obj == null || obj.getClass() != tclass || cclass != null || |
403 (newValue != null && vclass != null && |
403 (newValue != null && vclass != null && |
404 vclass != newValue.getClass())) |
404 vclass != newValue.getClass())) |
405 updateCheck(obj, newValue); |
405 updateCheck(obj, newValue); |
406 unsafe.putObjectVolatile(obj, offset, newValue); |
406 U.putObjectVolatile(obj, offset, newValue); |
407 } |
407 } |
408 |
408 |
409 public void lazySet(T obj, V newValue) { |
409 public void lazySet(T obj, V newValue) { |
410 if (obj == null || obj.getClass() != tclass || cclass != null || |
410 if (obj == null || obj.getClass() != tclass || cclass != null || |
411 (newValue != null && vclass != null && |
411 (newValue != null && vclass != null && |
412 vclass != newValue.getClass())) |
412 vclass != newValue.getClass())) |
413 updateCheck(obj, newValue); |
413 updateCheck(obj, newValue); |
414 unsafe.putOrderedObject(obj, offset, newValue); |
414 U.putOrderedObject(obj, offset, newValue); |
415 } |
415 } |
416 |
416 |
417 @SuppressWarnings("unchecked") |
417 @SuppressWarnings("unchecked") |
418 public V get(T obj) { |
418 public V get(T obj) { |
419 if (obj == null || obj.getClass() != tclass || cclass != null) |
419 if (obj == null || obj.getClass() != tclass || cclass != null) |
420 targetCheck(obj); |
420 targetCheck(obj); |
421 return (V)unsafe.getObjectVolatile(obj, offset); |
421 return (V)U.getObjectVolatile(obj, offset); |
422 } |
422 } |
423 |
423 |
424 @SuppressWarnings("unchecked") |
424 @SuppressWarnings("unchecked") |
425 public V getAndSet(T obj, V newValue) { |
425 public V getAndSet(T obj, V newValue) { |
426 if (obj == null || obj.getClass() != tclass || cclass != null || |
426 if (obj == null || obj.getClass() != tclass || cclass != null || |
427 (newValue != null && vclass != null && |
427 (newValue != null && vclass != null && |
428 vclass != newValue.getClass())) |
428 vclass != newValue.getClass())) |
429 updateCheck(obj, newValue); |
429 updateCheck(obj, newValue); |
430 return (V)unsafe.getAndSetObject(obj, offset, newValue); |
430 return (V)U.getAndSetObject(obj, offset, newValue); |
431 } |
431 } |
432 |
432 |
433 private void ensureProtectedAccess(T obj) { |
433 private void ensureProtectedAccess(T obj) { |
434 if (cclass.isInstance(obj)) { |
434 if (cclass.isInstance(obj)) { |
435 return; |
435 return; |