這裏看一下原子數組操做和一些其餘的原子操做。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也是比較簡單,可是也是有一些約束的。
以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