1 /*
   2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   3  *
   4  * This code is free software; you can redistribute it and/or modify it
   5  * under the terms of the GNU General Public License version 2 only, as
   6  * published by the Free Software Foundation.  Oracle designates this
   7  * particular file as subject to the "Classpath" exception as provided
   8  * by Oracle in the LICENSE file that accompanied this code.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 /*
  26  * This file is available under and governed by the GNU General Public
  27  * License version 2 only, as published by the Free Software Foundation.
  28  * However, the following notice accompanied the original version of this
  29  * file:
  30  *
  31  * Written by Doug Lea with assistance from members of JCP JSR-166
  32  * Expert Group and released to the public domain, as explained at
  33  * http://creativecommons.org/licenses/publicdomain
  34  */
  35 
  36 package java.util.concurrent.atomic;
  37 import sun.misc.Unsafe;
  38 import java.lang.reflect.*;
  39 
  40 /**
  41  * A reflection-based utility that enables atomic updates to
  42  * designated {@code volatile} reference fields of designated
  43  * classes.  This class is designed for use in atomic data structures
  44  * in which several reference fields of the same node are
  45  * independently subject to atomic updates. For example, a tree node
  46  * might be declared as
  47  *
  48  *  <pre> {@code
  49  * class Node {
  50  *   private volatile Node left, right;
  51  *
  52  *   private static final AtomicReferenceFieldUpdater<Node, Node> leftUpdater =
  53  *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "left");
  54  *   private static AtomicReferenceFieldUpdater<Node, Node> rightUpdater =
  55  *     AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "right");
  56  *
  57  *   Node getLeft() { return left;  }
  58  *   boolean compareAndSetLeft(Node expect, Node update) {
  59  *     return leftUpdater.compareAndSet(this, expect, update);
  60  *   }
  61  *   // ... and so on
  62  * }}</pre>

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