zoukankan      html  css  js  c++  java
  • Java多线程系列--“JUC原子类”05之 AtomicLongFieldUpdater原子类

    概要

    AtomicIntegerFieldUpdater, AtomicLongFieldUpdater和AtomicReferenceFieldUpdater这3个修改类的成员的原子类型的原理和用法相似。本章以对基本类型的原子类进行介绍。内容包括:
    AtomicLongFieldUpdater介绍和函数列表
    AtomicLongFieldUpdater示例
    AtomicLongFieldUpdater源码分析(基于JDK1.7.0_40)

    转载请注明出处:http://www.cnblogs.com/skywang12345/p/3514623.html

     

    AtomicLongFieldUpdater介绍和函数列表

    AtomicLongFieldUpdater可以对指定"类的 'volatile long'类型的成员"进行原子更新。它是基于反射原理实现的。

    AtomicLongFieldUpdater函数列表

    // 受保护的无操作构造方法,供子类使用。
    protected AtomicLongFieldUpdater()
    
    // 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。
    long addAndGet(T obj, long delta)
    // 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。
    abstract boolean compareAndSet(T obj, long expect, long update)
    // 以原子方式将此更新器管理的给定对象字段当前值减 1。
    long decrementAndGet(T obj)
    // 获取此更新器管理的在给定对象的字段中保持的当前值。
    abstract long get(T obj)
    // 以原子方式将给定值添加到此更新器管理的给定对象的字段的当前值。
    long getAndAdd(T obj, long delta)
    // 以原子方式将此更新器管理的给定对象字段当前值减 1。
    long getAndDecrement(T obj)
    // 以原子方式将此更新器管理的给定对象字段的当前值加 1。
    long getAndIncrement(T obj)
    // 将此更新器管理的给定对象的字段以原子方式设置为给定值,并返回旧值。
    long getAndSet(T obj, long newValue)
    // 以原子方式将此更新器管理的给定对象字段当前值加 1。
    long incrementAndGet(T obj)
    // 最后将此更新器管理的给定对象的字段设置为给定更新值。
    abstract void lazySet(T obj, long newValue)
    // 为对象创建并返回一个具有给定字段的更新器。
    static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName)
    // 将此更新器管理的给定对象的字段设置为给定更新值。
    abstract void set(T obj, long newValue)
    // 如果当前值 == 预期值,则以原子方式将此更新器所管理的给定对象的字段设置为给定的更新值。
    abstract boolean weakCompareAndSet(T obj, long expect, long update)

    AtomicLongFieldUpdater示例

    // LongTest.java的源码
    import java.util.concurrent.atomic.AtomicLongFieldUpdater;
    
    public class LongFieldTest {
        
        public static void main(String[] args) {
    
            // 获取Person的class对象
            Class cls = Person.class; 
            // 新建AtomicLongFieldUpdater对象,传递参数是“class对象”和“long类型在类中对应的名称”
            AtomicLongFieldUpdater mAtoLong = AtomicLongFieldUpdater.newUpdater(cls, "id");
            Person person = new Person(12345678L);
    
            // 比较person的"id"属性,如果id的值为12345678L,则设置为1000。
            mAtoLong.compareAndSet(person, 12345678L, 1000);
            System.out.println("id="+person.getId());
        }
    }
    
    class Person {
        volatile long id;
        public Person(long id) {
            this.id = id;
        }
        public void setId(long id) {
            this.id = id;
        }
        public long getId() {
            return id;
        }
    }

    运行结果

    id=1000

    AtomicLongFieldUpdater源码分析(基于JDK1.7.0_40)

    AtomicLongFieldUpdater完整源码

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

    下面分析LongFieldTest.java的流程。

    1. newUpdater()
    newUpdater()的源码如下:

    public static <U> AtomicLongFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
        Class<?> caller = Reflection.getCallerClass();
        if (AtomicLong.VM_SUPPORTS_LONG_CAS)
            return new CASUpdater<U>(tclass, fieldName, caller);
        else
            return new LockedUpdater<U>(tclass, fieldName, caller);
    }

    说明:newUpdater()的作用是获取一个AtomicIntegerFieldUpdater类型的对象。
    它实际上返回的是CASUpdater对象,或者LockedUpdater对象;具体返回哪一个类取决于JVM是否支持long类型的CAS函数。CASUpdater和LockedUpdater都是AtomicIntegerFieldUpdater的子类,它们的实现类似。下面以CASUpdater来进行说明。

    CASUpdater类的源码如下:

    public boolean compareAndSet(T obj, long expect, long update) {
        if (obj == null || obj.getClass() != tclass || cclass != null) fullCheck(obj);
        return unsafe.compareAndSwapLong(obj, offset, expect, update);
    }

    说明:它实际上是通过CAS函数操作。如果类的long对象的值是expect,则设置它的值为update。 


    更多内容

    1. Java多线程系列--“JUC原子类”01之 框架

    2. Java多线程系列--“JUC原子类”02之 AtomicLong原子类

    3. Java多线程系列--“JUC原子类”03之 AtomicLongArray原子类

    4. Java多线程系列--“JUC原子类”04之 AtomicReference原子类

    5. Java多线程系列目录(共xx篇)

  • 相关阅读:
    leetcode443
    leetcode429
    leetcode55
    2019-8-31-PowerShell-拿到最近的10个系统日志
    2019-6-11-WPF-如何在应用程序调试启动
    2019-8-31-C#-将-Begin-和-End-异步方法转-task-异步
    2019-9-18-WPF-笔刷绑定不上可能的原因
    2019-3-25-win10-uwp-如何将像素数组转-png-文件
    2018-9-30-C#-从零开始写-SharpDx-应用-画三角
    2018-8-10-Roslyn-节点的-Span-和--FullSpan-有什么区别
  • 原文地址:https://www.cnblogs.com/skywang12345/p/3514635.html
Copyright © 2011-2022 走看看