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

相關文章
相關標籤/搜索