Source for java.util.concurrent.atomic.AtomicReferenceFieldUpdater

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