(一)先聊聊AtomicLong的基本概念,然後聊一下他的缺陷問題,然後引出LongAdder的優點
(1)大家都使用過AtomicInteger、AtomicLong等這幾類原子性的工具類,具體怎麼用我就不說了,就說一下他們的大概的基本實現原理
- 其實這些基本的原子操作的思想大體都是,
expect 表示當前內存中你所預期望的值,update 是你想要更新的值
public final boolean compareAndSet(long expect, long update) {
這個this表示了當前對象的地址,後面的valueOffset是在該對象開始的位置加上這個valueOffset的偏移量,就能拿到的是當前對象的值
return unsafe.compareAndSwapLong(this, valueOffset, expect, update);
}
- 然後這裏又會去調用unsafe對象的native方法,這個是基於C寫的代碼
把上面的compareAndSwapLong的入參和這個對應起來,然後其實就是判斷當前位置的值,是不是和你預期的expect的值相等,如果相等就把valueOffset處的值更新爲update你想要更新的結果,
如果失敗的話,就不做改變(說明這個值跟你期望的不一致,就意味着這個值被別的線程修改過了,就什麼也不操作)
public final native boolean compareAndSwapLong(Object var1,
long var2,
long var4,
long var6);
(2)這樣帶來的缺點就是,如果有大量的線程進行CAS的時候,那麼就會導致大量的線程都在進行CAS,但是能夠成功的又很少,那麼就會出現有大量線程進行自旋,並且對CPU造成大量的資源消耗的缺點,所以這個時候就進行了優化,那麼就出現了LongAdder
- 但是如果要是在併發度不是很高的情況下,其實使用LongAdder和AtomicLong的差別不大
- 儘量減少熱點衝突,不到最後萬不得已,儘量將CAS操作延遲
(二)先說一下LongAdder的整體設計思想
(1)其實整體的設計思想就是:如果在如果有很多個線程來進行CAS的時候,而在LongAdder中他其實是借鑑的了HashMap1.7的思想,他把這個資源進行分段來進行維護,他內部維護了一個Cell[]數組,每個Cell對象中就包含了資源的值,其實就是和HashMap中的那個table數組,table數組中放的都是包含key-value的一個Node對象
(2)然後在競爭激烈的時候就直接懟base值進行增加,但是如果當線程競爭足夠激烈的時候就會統計每個線程對應的Cell[這個是每個線程的hash出來的一個下標值]進行相加
value=base+∑i=0nCell[i]
(3)主要的Add方法
(4)如果
參考:https://segmentfault.com/a/1190000015865714#articleHeader4