/** * Atomically increments by one the current value. * * @return the updated value */ public final long incrementAndGet() { return unsafe.getAndAddLong(this, valueOffset, 1L) + 1L; }
public final long getAndAddLong(Object var1, long var2, long var4) { long var6; do { var6 = this.getLongVolatile(var1, var2); } while(!this.compareAndSwapLong(var1, var2, var6, var6 + var4)); // 關注重點:if(var2 == var6) return var6; }
var1
調用原方法 incrementAndGet
即自身的對象var2
原對象當前(工做內存中的)值var4
要加上去的值var6
調用底層方法 getLongVolatile
得到當前(主內存中的)值,若是沒其餘線程修改即與 var2
相等var2
與 var6
爲何可能會不同?html
var2
與主內存中的值 var6
之間的可能不同(JMM)// 獲取主內存裏的值 public native long getLongVolatile(Object var1, long var2); // CAS 操做 public final native boolean compareAndSwapLong(Object var1, long var2, long var4, long var6);
native關鍵字說明其修飾的方法是一個原生態方法,方法對應的實現不是在當前文件,而是在用其餘語言(如 C 和 C++)實現的文件中。Java 語言自己不能對操做系統底層進行訪問和操做,可是能夠經過JNI接口調用其餘語言來實現對底層的訪問。
public void increment() { add(1L); } public void add(long x) { Cell[] as; long b, v; int m; Cell a; if ((as = cells) != null || !casBase(b = base, b + x)) { boolean uncontended = true; if (as == null || (m = as.length - 1) < 0 || (a = as[getProbe() & m]) == null || !(uncontended = a.cas(v = a.value, v + x))) longAccumulate(x, null, uncontended); // <- 重點 } }
Cell
類,是一個普通的二元算術累積單元,它在 Striped64
裏面。Striped64
這個類使用分段的思想,來儘可能平攤併發壓力(相似1.7及之前版本的 ConcurrentHashMap.Segment
)。compareAndSwapLong
來更新值。/** * Padded variant of AtomicLong supporting only raw accesses plus CAS. * * JVM intrinsics note: It would be possible to use a release-only * form of CAS here, if it were provided. */ @sun.misc.Contended static final class Cell { volatile long value; Cell(long x) { value = x; } final boolean cas(long cmp, long val) { return UNSAFE.compareAndSwapLong(this, valueOffset, cmp, val); } // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE; private static final long valueOffset; static { try { UNSAFE = sun.misc.Unsafe.getUnsafe(); Class<?> ak = Cell.class; valueOffset = UNSAFE.objectFieldOffset (ak.getDeclaredField("value")); } catch (Exception e) { throw new Error(e); } } }
Long
映射到 Cell[]
數組裏面,經過 Hash
等算法映射到其中一個數字進行計數,而最終的計數結果就是其求和累加。在低併發的時候,經過對 base
的直接更新,能夠很好地保證和 Atomic
性能的基本一致;而在高併發的時候,則將單點的更新壓力分散到各個節點上,提高了性能。AtomicLong
適用於序號生成,這種狀況下須要準確的、全局惟一的數值;但在高併發狀況下的計數操做,使用 AtomicLong
時會因線程競爭致使失敗白白循環一次;失敗次數越多,循環次數也越多。此時使用LongAdder
能更好地提高性能。LongAdder
適用於高併發狀況下的計數操做,利用與 JDK1.7 ConcurrentHashMap
類似的原理,以空間換時間,提升了實際的計數效率。固然,線程競爭很低的狀況下進行計數,使用 AtomicLong
仍是更簡單更直接,而且效率稍微高一些。注意:CAS 是 sun.misc.Unsafe
中提供的操做,只對 int、long、對象類型(引用或者指針)提供了這種操做,其餘類型都須要轉化爲這三種類型才能進行 CAS 操做。(例如 DoubleAdder
就是 LongAdder
的簡單改造,主要的變化就是用 Double.longBitsToDouble
和 Double.doubleToRawLongBits
對底層的8字節數據進行 long <=> double
轉換,存儲的時候使用 long 型,計算的時候轉化爲 double 型。)java
參考資料算法