jdk/src/java.base/share/classes/java/util/concurrent/atomic/AtomicReferenceFieldUpdater.java
changeset 32838 caeef2c79243
parent 25859 3317bb8137f4
child 33674 566777f73c32
equal deleted inserted replaced
32837:e331a1a5a621 32838:caeef2c79243
    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>
   282         return next;
   282         return next;
   283     }
   283     }
   284 
   284 
   285     private static final class AtomicReferenceFieldUpdaterImpl<T,V>
   285     private static final class AtomicReferenceFieldUpdaterImpl<T,V>
   286         extends AtomicReferenceFieldUpdater<T,V> {
   286         extends AtomicReferenceFieldUpdater<T,V> {
   287         private static final Unsafe unsafe = Unsafe.getUnsafe();
   287         private static final sun.misc.Unsafe U = sun.misc.Unsafe.getUnsafe();
   288         private final long offset;
   288         private final long offset;
   289         private final Class<T> tclass;
   289         private final Class<T> tclass;
   290         private final Class<V> vclass;
   290         private final Class<V> vclass;
   291         private final Class<?> cclass;
   291         private final Class<?> cclass;
   292 
   292 
   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) {
   345             this.tclass = tclass;
   345             this.tclass = tclass;
   346             if (vclass == Object.class)
   346             if (vclass == Object.class)
   347                 this.vclass = null;
   347                 this.vclass = null;
   348             else
   348             else
   349                 this.vclass = vclass;
   349                 this.vclass = vclass;
   350             offset = unsafe.objectFieldOffset(field);
   350             offset = U.objectFieldOffset(field);
   351         }
   351         }
   352 
   352 
   353         /**
   353         /**
   354          * Returns true if the second classloader can be found in the first
   354          * Returns true if the second classloader can be found in the first
   355          * classloader's delegation chain.
   355          * classloader's delegation chain.
   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;