Home | History | Annotate | Download | only in atomic
      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/publicdomain/zero/1.0/
      5  */
      6 
      7 package java.util.concurrent.atomic;
      8 
      9 import dalvik.system.VMStack; // android-added
     10 import sun.misc.Unsafe;
     11 import java.lang.reflect.*;
     12 
     13 /**
     14  * A reflection-based utility that enables atomic updates to
     15  * designated {@code volatile long} fields of designated classes.
     16  * This class is designed for use in atomic data structures in which
     17  * several fields of the same node are independently subject to atomic
     18  * updates.
     19  *
     20  * <p>Note that the guarantees of the {@code compareAndSet}
     21  * method in this class are weaker than in other atomic classes.
     22  * Because this class cannot ensure that all uses of the field
     23  * are appropriate for purposes of atomic access, it can
     24  * guarantee atomicity only with respect to other invocations of
     25  * {@code compareAndSet} and {@code set} on the same updater.
     26  *
     27  * @since 1.5
     28  * @author Doug Lea
     29  * @param <T> The type of the object holding the updatable field
     30  */
     31 public abstract class  AtomicLongFieldUpdater<T> {
     32     /**
     33      * Creates and returns an updater for objects with the given field.
     34      * The Class argument is needed to check that reflective types and
     35      * generic types match.
     36      *
     37      * @param tclass the class of the objects holding the field
     38      * @param fieldName the name of the field to be updated.
     39      * @return the updater
     40      * @throws IllegalArgumentException if the field is not a
     41      * volatile long type.
     42      * @throws RuntimeException with a nested reflection-based
     43      * exception if the class does not hold field or is the wrong type.
     44      */
     45     public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
     46         if (AtomicLong.VM_SUPPORTS_LONG_CAS)
     47             return new CASUpdater<U>(tclass, fieldName);
     48         else
     49             return new LockedUpdater<U>(tclass, fieldName);
     50     }
     51 
     52     /**
     53      * Protected do-nothing constructor for use by subclasses.
     54      */
     55     protected AtomicLongFieldUpdater() {
     56     }
     57 
     58     /**
     59      * Atomically sets the field of the given object managed by this updater
     60      * to the given updated value if the current value {@code ==} the
     61      * expected value. This method is guaranteed to be atomic with respect to
     62      * other calls to {@code compareAndSet} and {@code set}, but not
     63      * necessarily with respect to other changes in the field.
     64      *
     65      * @param obj An object whose field to conditionally set
     66      * @param expect the expected value
     67      * @param update the new value
     68      * @return true if successful.
     69      * @throws ClassCastException if {@code obj} is not an instance
     70      * of the class possessing the field established in the constructor.
     71      */
     72     public abstract boolean compareAndSet(T obj, long expect, long update);
     73 
     74     /**
     75      * Atomically sets the field of the given object managed by this updater
     76      * to the given updated value if the current value {@code ==} the
     77      * expected value. This method is guaranteed to be atomic with respect to
     78      * other calls to {@code compareAndSet} and {@code set}, but not
     79      * necessarily with respect to other changes in the field.
     80      *
     81      * <p>May <a href="package-summary.html#Spurious">fail spuriously</a>
     82      * and does not provide ordering guarantees, so is only rarely an
     83      * appropriate alternative to {@code compareAndSet}.
     84      *
     85      * @param obj An object whose field to conditionally set
     86      * @param expect the expected value
     87      * @param update the new value
     88      * @return true if successful.
     89      * @throws ClassCastException if {@code obj} is not an instance
     90      * of the class possessing the field established in the constructor.
     91      */
     92     public abstract boolean weakCompareAndSet(T obj, long expect, long update);
     93 
     94     /**
     95      * Sets the field of the given object managed by this updater to the
     96      * given updated value. This operation is guaranteed to act as a volatile
     97      * store with respect to subsequent invocations of {@code compareAndSet}.
     98      *
     99      * @param obj An object whose field to set
    100      * @param newValue the new value
    101      */
    102     public abstract void set(T obj, long newValue);
    103 
    104     /**
    105      * Eventually sets the field of the given object managed by this
    106      * updater to the given updated value.
    107      *
    108      * @param obj An object whose field to set
    109      * @param newValue the new value
    110      * @since 1.6
    111      */
    112     public abstract void lazySet(T obj, long newValue);
    113 
    114     /**
    115      * Gets the current value held in the field of the given object managed
    116      * by this updater.
    117      *
    118      * @param obj An object whose field to get
    119      * @return the current value
    120      */
    121     public abstract long get(T obj);
    122 
    123     /**
    124      * Atomically sets the field of the given object managed by this updater
    125      * to the given value and returns the old value.
    126      *
    127      * @param obj An object whose field to get and set
    128      * @param newValue the new value
    129      * @return the previous value
    130      */
    131     public long getAndSet(T obj, long newValue) {
    132         for (;;) {
    133             long current = get(obj);
    134             if (compareAndSet(obj, current, newValue))
    135                 return current;
    136         }
    137     }
    138 
    139     /**
    140      * Atomically increments by one the current value of the field of the
    141      * given object managed by this updater.
    142      *
    143      * @param obj An object whose field to get and set
    144      * @return the previous value
    145      */
    146     public long getAndIncrement(T obj) {
    147         for (;;) {
    148             long current = get(obj);
    149             long next = current + 1;
    150             if (compareAndSet(obj, current, next))
    151                 return current;
    152         }
    153     }
    154 
    155     /**
    156      * Atomically decrements by one the current value of the field of the
    157      * given object managed by this updater.
    158      *
    159      * @param obj An object whose field to get and set
    160      * @return the previous value
    161      */
    162     public long getAndDecrement(T obj) {
    163         for (;;) {
    164             long current = get(obj);
    165             long next = current - 1;
    166             if (compareAndSet(obj, current, next))
    167                 return current;
    168         }
    169     }
    170 
    171     /**
    172      * Atomically adds the given value to the current value of the field of
    173      * the given object managed by this updater.
    174      *
    175      * @param obj An object whose field to get and set
    176      * @param delta the value to add
    177      * @return the previous value
    178      */
    179     public long getAndAdd(T obj, long delta) {
    180         for (;;) {
    181             long current = get(obj);
    182             long next = current + delta;
    183             if (compareAndSet(obj, current, next))
    184                 return current;
    185         }
    186     }
    187 
    188     /**
    189      * Atomically increments by one the current value of the field of the
    190      * given object managed by this updater.
    191      *
    192      * @param obj An object whose field to get and set
    193      * @return the updated value
    194      */
    195     public long incrementAndGet(T obj) {
    196         for (;;) {
    197             long current = get(obj);
    198             long next = current + 1;
    199             if (compareAndSet(obj, current, next))
    200                 return next;
    201         }
    202     }
    203 
    204     /**
    205      * Atomically decrements by one the current value of the field of the
    206      * given object managed by this updater.
    207      *
    208      * @param obj An object whose field to get and set
    209      * @return the updated value
    210      */
    211     public long decrementAndGet(T obj) {
    212         for (;;) {
    213             long current = get(obj);
    214             long next = current - 1;
    215             if (compareAndSet(obj, current, next))
    216                 return next;
    217         }
    218     }
    219 
    220     /**
    221      * Atomically adds the given value to the current value of the field of
    222      * the given object managed by this updater.
    223      *
    224      * @param obj An object whose field to get and set
    225      * @param delta the value to add
    226      * @return the updated value
    227      */
    228     public long addAndGet(T obj, long delta) {
    229         for (;;) {
    230             long current = get(obj);
    231             long next = current + delta;
    232             if (compareAndSet(obj, current, next))
    233                 return next;
    234         }
    235     }
    236 
    237     private static class CASUpdater<T> extends AtomicLongFieldUpdater<T> {
    238         private static final Unsafe unsafe = Unsafe.getUnsafe();
    239         private final long offset;
    240         private final Class<T> tclass;
    241         private final Class<?> cclass;
    242 
    243         CASUpdater(Class<T> tclass, String fieldName) {
    244             Field field = null;
    245             Class<?> caller = null;
    246             int modifiers = 0;
    247             try {
    248                 field = tclass.getDeclaredField(fieldName);
    249                 caller = VMStack.getStackClass2(); // android-changed
    250                 modifiers = field.getModifiers();
    251                 // BEGIN android-removed
    252                 // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
    253                 //     caller, tclass, null, modifiers);
    254                 // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
    255                 // END android-removed
    256             } catch (Exception ex) {
    257                 throw new RuntimeException(ex);
    258             }
    259 
    260             Class<?> fieldt = field.getType();
    261             if (fieldt != long.class)
    262                 throw new IllegalArgumentException("Must be long type");
    263 
    264             if (!Modifier.isVolatile(modifiers))
    265                 throw new IllegalArgumentException("Must be volatile type");
    266 
    267             this.cclass = (Modifier.isProtected(modifiers) &&
    268                            caller != tclass) ? caller : null;
    269             this.tclass = tclass;
    270             offset = unsafe.objectFieldOffset(field);
    271         }
    272 
    273         private void fullCheck(T obj) {
    274             if (!tclass.isInstance(obj))
    275                 throw new ClassCastException();
    276             if (cclass != null)
    277                 ensureProtectedAccess(obj);
    278         }
    279 
    280         public boolean compareAndSet(T obj, long expect, long update) {
    281             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    282             return unsafe.compareAndSwapLong(obj, offset, expect, update);
    283         }
    284 
    285         public boolean weakCompareAndSet(T obj, long expect, long update) {
    286             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    287             return unsafe.compareAndSwapLong(obj, offset, expect, update);
    288         }
    289 
    290         public void set(T obj, long newValue) {
    291             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    292             unsafe.putLongVolatile(obj, offset, newValue);
    293         }
    294 
    295         public void lazySet(T obj, long newValue) {
    296             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    297             unsafe.putOrderedLong(obj, offset, newValue);
    298         }
    299 
    300         public long get(T obj) {
    301             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    302             return unsafe.getLongVolatile(obj, offset);
    303         }
    304 
    305         private void ensureProtectedAccess(T obj) {
    306             if (cclass.isInstance(obj)) {
    307                 return;
    308             }
    309             throw new RuntimeException(
    310                 new IllegalAccessException("Class " +
    311                     cclass.getName() +
    312                     " can not access a protected member of class " +
    313                     tclass.getName() +
    314                     " using an instance of " +
    315                     obj.getClass().getName()
    316                 )
    317             );
    318         }
    319     }
    320 
    321 
    322     private static class LockedUpdater<T> extends AtomicLongFieldUpdater<T> {
    323         private static final Unsafe unsafe = Unsafe.getUnsafe();
    324         private final long offset;
    325         private final Class<T> tclass;
    326         private final Class<?> cclass;
    327 
    328         LockedUpdater(Class<T> tclass, String fieldName) {
    329             Field field = null;
    330             Class<?> caller = null;
    331             int modifiers = 0;
    332             try {
    333                 field = tclass.getDeclaredField(fieldName);
    334                 caller = VMStack.getStackClass2(); // android-changed
    335                 modifiers = field.getModifiers();
    336                 // BEGIN android-removed
    337                 // sun.reflect.misc.ReflectUtil.ensureMemberAccess(
    338                 //     caller, tclass, null, modifiers);
    339                 // sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass);
    340                 // END android-removed
    341             } catch (Exception ex) {
    342                 throw new RuntimeException(ex);
    343             }
    344 
    345             Class<?> fieldt = field.getType();
    346             if (fieldt != long.class)
    347                 throw new IllegalArgumentException("Must be long type");
    348 
    349             if (!Modifier.isVolatile(modifiers))
    350                 throw new IllegalArgumentException("Must be volatile type");
    351 
    352             this.cclass = (Modifier.isProtected(modifiers) &&
    353                            caller != tclass) ? caller : null;
    354             this.tclass = tclass;
    355             offset = unsafe.objectFieldOffset(field);
    356         }
    357 
    358         private void fullCheck(T obj) {
    359             if (!tclass.isInstance(obj))
    360                 throw new ClassCastException();
    361             if (cclass != null)
    362                 ensureProtectedAccess(obj);
    363         }
    364 
    365         public boolean compareAndSet(T obj, long expect, long update) {
    366             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    367             synchronized (this) {
    368                 long v = unsafe.getLong(obj, offset);
    369                 if (v != expect)
    370                     return false;
    371                 unsafe.putLong(obj, offset, update);
    372                 return true;
    373             }
    374         }
    375 
    376         public boolean weakCompareAndSet(T obj, long expect, long update) {
    377             return compareAndSet(obj, expect, update);
    378         }
    379 
    380         public void set(T obj, long newValue) {
    381             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    382             synchronized (this) {
    383                 unsafe.putLong(obj, offset, newValue);
    384             }
    385         }
    386 
    387         public void lazySet(T obj, long newValue) {
    388             set(obj, newValue);
    389         }
    390 
    391         public long get(T obj) {
    392             if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
    393             synchronized (this) {
    394                 return unsafe.getLong(obj, offset);
    395             }
    396         }
    397 
    398         private void ensureProtectedAccess(T obj) {
    399             if (cclass.isInstance(obj)) {
    400                 return;
    401             }
    402             throw new RuntimeException(
    403                 new IllegalAccessException("Class " +
    404                     cclass.getName() +
    405                     " can not access a protected member of class " +
    406                     tclass.getName() +
    407                     " using an instance of " +
    408                     obj.getClass().getName()
    409                 )
    410             );
    411         }
    412     }
    413 }
    414