J.U.C atomic 数组,字段原子操做

    这里看一下原子数组操做和一些其余的原子操做。html

    AtomicIntegerArray/AtomicLongArray/AtomicReferenceArray的API相似,选择表明性的AtomicIntegerArray来描述这些问题。java

    

int get(int i) //得到当前位置的值
void set(int i, int newValue) //设置给定位置的值
void lazySet(int i, int newValue)
int getAndSet(int i, int newValue)
boolean compareAndSet(int i, int expect, int update)
boolean weakCompareAndSet(int i, int expect, int update)
int getAndIncrement(int i)
int getAndDecrement(int i)
int getAndAdd(int i, int delta)
int incrementAndGet(int i)
int decremnetAndGet(int i)
int addAndGet(int i, int delta)

    这些API和AtomicInteger是相似的,区别是这里是数组操做,因此多个索引参数。数组

    因为这个是数组操做,就存在数组越界的问题(IndexOutBoundsException异常),因此在get/set方法前都会检查int index是否合法。先来看看该类的主要成员.缓存

    private static final Unsafe unsafe = Unsafe.getUnsafe();
    private static final int base = unsafe.arrayBaseOffset(int[].class);
    private static final int shift;
    private final int[] array;

   Unsafe.getUndafe()就不说了,CAS操做少不了他;数据结构

   base :经过Unsafe得到数组的基址;并发

   shift : 数组每一个元素在内存的偏移量;this

   array : 底层实际操做数组;spa

  static {
        int scale = unsafe.arrayIndexScale(int[].class);          //数组元素的大小,必须为2^x大小
        if ((scale & (scale - 1)) != 0)
            throw new Error("data type scale not a power of two");
        shift = 31 - Integer.numberOfLeadingZeros(scale);   //数组元素的bit偏移量
    }

   数组index检查:.net

   private long checkedByteOffset(int i) {
        if (i < 0 || i >= array.length)      //索引index越界。throw 异常
            throw new IndexOutOfBoundsException("index " + i);

        return byteOffset(i);
    }

    private static long byteOffset(int i) {     //取得指定index元素的内存位置(base + offset)
        return ((long) i << shift) + base;
    }

   set/get时进行index检查:code

 public final int get(int i) {
        return getRaw(checkedByteOffset(i));
    }

 public final void set(int i, int newValue) {
        unsafe.putIntVolatile(array, checkedByteOffset(i), newValue);
    }

<********************************************************字段*********************************************************************>

       AtomicIntegerFieldUpdater<T>/AtomicLongFieldUpdater<T>/AtomicReferenceFieldUpdate<T,V>

     上面三种是基于反射的原子更新字段的值。

     相应的API也是比较简单,可是也是有一些约束的。

  1.    字段必须是volatile类型的!
  2.    字段的描述类型(修饰符public/protected/default/private)做用于调用者与操做对象的关系。即调用者可以直接操做对象字段,那么就能够反射进行原子操做证。private类型字段,调用者没法访问,更新该变量,protected类型变量成员,当操做对象为调用者class的实例或者子类时,能够访问,原子更新protected成员。
  3.    只能是实例变量,不能是类变量,也就是说不能加static关键字。
  4.    只能是可修改变量,不能使用final变量,由于final的语义就是不可修改。实际上final语义和volatile是由冲突的,这两关键字不能同时存在
  5.    对于AtomicIntegerFieldUpdater和AtomicLongFieldUpdater只能修改int/long类型字段,不能修改其包装器类型(Integer/Long)。若是要修改包装器类型须要使用AtomicReferenceFieldUpdater。

   

      以AtomicIntegerFieldUpdater为例:

public static <U> AtomicIntegerFieldUpdater<U> newUpdater(Class<U> tclass, String fieldName) {
        return new AtomicIntegerFieldUpdaterImpl<U>(tclass, fieldName, Reflection.getCallerClass());
    }

     AtomicIntegerFieldUpdater为一个抽象类,经过static newUpdater()方法得到其实现类实例,参数为操做对象Class对象,和其变量成员名:

public abstract class  AtomicIntegerFieldUpdater<T>

private static class AtomicIntegerFieldUpdaterImpl<T> extends AtomicIntegerFieldUpdater<T>

    AtomicIntegerFieldUpdater的抽象方法定义以下:

    public abstract boolean compareAndSet(T obj, int expect, int update);

    public abstract boolean weakCompareAndSet(T obj, int expect, int update);

    public abstract void set(T obj, int newValue);

    public abstract void lazySet(T obj, int newValue);

    public abstract int get(T obj);

    再来看看其实现类内部:

        private final long offset; //成员变量的内存偏移量
        private final Class<T> tclass; //操做对象的class对象
        private final Class cclass;  //调用者class对象

   在进行成员更新访问时,都必须进行所谓的访问权限检查,上面几点以说明:

  sun.reflect.misc.ReflectUtil.ensureMemberAccess( //成员变量访问权限的肯定(排除private)
        caller, tclass, null, modifiers);
  sun.reflect.misc.ReflectUtil.checkPackageAccess(tclass); //包访问权限


Class fieldt = field.getType(); if (fieldt != int.class) throw new IllegalArgumentException("Must be integer type"); //变量成员的类型必须为int if (!Modifier.isVolatile(modifiers)) //变量成员必需要关键字volatile修饰。 throw new IllegalArgumentException("Must be volatile type"); this.cclass = (Modifier.isProtected(modifiers) && //1.当成员为protected时,赋值 cclass = caller(赋值调用者class对象) 2:不为protected时,赋值 cclass = null. caller != tclass) ? caller : null;

 

 private void fullCheck(T obj) {
            if (!tclass.isInstance(obj))  //操做对象不为newUpdate()传入的class的实例或子类时,throw. 
                throw new ClassCastException();
            if (cclass != null)  //上面以分析,当成员没有proteced修饰时, cclass 为null,因此不要进一步检查,直接放行,
                ensureProtectedAccess(obj);
        }

     当变量为proteced修饰时:

 private void ensureProtectedAccess(T obj) {
            if (cclass.isInstance(obj)) {  //当要原子操做的对象obj为调用者class的实例或者子类时,放行,运行原子操做,不然Throw。
                return;
            }
            throw new RuntimeException(
                new IllegalAccessException("Class " +
                    cclass.getName() +
                    " can not access a protected member of class " +
                    tclass.getName() +
                    " using an instance of " +
                    obj.getClass().getName()
                )
            );
        }

 

       AtomicMarkableReference类描述的一个<Object, Boolean>的pair,能够原子的修改object或者boolean的值,这种数据结构在一些缓存或者章台描述中比较有用。这种结构在单个或者同时修改Object/Boolean的时候可以有效的提升吞吐量。

 

private static class Pair<T> {
        final T reference;
        final boolean mark;
        private Pair(T reference, boolean mark) {
            this.reference = reference;
            this.mark = mark;
        }
        static <T> Pair<T> of(T reference, boolean mark) {
            return new Pair<T>(reference, mark);
        }
    }

private volatile Pair<V> pair;

    看看它的cas操做:

 public boolean compareAndSet(V       expectedReference,
                                 V       newReference,
                                 boolean expectedMark,
                                 boolean newMark) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&  //在expectReference == current.Ref && expectMark == current.mark 而且新值pair中有任意一个或者两个都不等于目前值时,才更新
            expectedMark == current.mark &&
            ((newReference == current.reference &&
              newMark == current.mark) ||
             casPair(current, Pair.of(newReference, newMark)));
    }

       AtomicStampedReference类维护带有整数”标志“的对象引用,能够用原子方法对其进行更新。对比AtomicMarkableReference类的pair<Object, Boolean>,AtomicStampedReference维护的是一种相似于<Object, Integer>的数据结构,实际上是对对象引用的一个并发计数

 private static class Pair<T> {
        final T reference;
        final int stamp;
        private Pair(T reference, int stamp) {
            this.reference = reference;
            this.stamp = stamp;
        }
        static <T> Pair<T> of(T reference, int stamp) {
            return new Pair<T>(reference, stamp);
        }
    }

    private volatile Pair<V> pair;
  public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            expectedReference == current.reference &&
            expectedStamp == current.stamp &&
            ((newReference == current.reference &&
              newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }

 

       两种在解决CAS ”ABA“问题上颇有用。

 

 参考:http://www.blogjava.net/xylz/archive/2010/07/02/325079.html

相关文章
相关标签/搜索