最近在看到不少框架裡面使用到了longadder這個類,而並非atomiclong,很是困惑,於是專門看了longadder的原始碼,總結一下這兩個的區別。
就像我們所知道的那樣,atomiclong的原理是依靠底層的cas來保障原子性的更新資料,在要新增或者減少的時候,會使用死迴圈不斷地cas到特定的值,從而達到更新資料的目的。那麼longadder又是使用到了什麼原理?難道有比cas更加快速的方式?
首先我們來看一下longadder有哪些方法?
可以看到和atomiclong基本類似,同樣有增加、減少等操作,那麼如何實現原子的增加呢?
我們可以看到乙個cell的類,那這個類是用來幹什麼的呢?
我們可以看到cell類的內部是乙個volatile的變數,然後更改這個變數唯一的方式通過cas。我們可以猜測到longadder的高明之處可能在於將之前單個節點的併發分散到各個節點的,這樣從而提高在高併發時候的效率。
下面我們來驗證我們的觀點,我們接著看上圖的add方法,如果cell陣列不為空,那麼就嘗試更新base元素,如果更新成功,那麼就直接返回。base元素在這裡起到了乙個什麼作用呢?可以保障的是在低併發的時候和atomiclong一樣的直接對基礎元素進行更新。
而如果cell為空或者更新base失敗,我們看接下來的那個if判斷,即如果as不為空並且成功更新對應節點的資料,則返回,否則就會進入longaccumulate()方法。
圖有點大,無法截圖,直接貼原始碼
for (;;)
} finally
if (created)
break;
continue; // slot is now non-empty}}
collide = false;
}else
if (!wasuncontended) //標示衝突標誌位 ,進行重試 cas already known to fail
wasuncontended = true; // continue after rehash
else
if (a.cas(v = a.value, ((fn == null) ? v + x :
break;
else
if (n >= ncpu || cells != as)
collide = false; // at max size or stale,如果已經cell陣列的大小已經超過了cpu核數,那麼再擴容沒意義了,直接重試,或者有別的執行緒擴容導致變更了陣列,設定標示位,進行重試,,避免一失敗就擴容
else
if (!collide)
collide = true;
else
if (cellsbusy == 0 && cascellsbusy())
} finally
collide = false;
continue; // retry with expanded table
}h = advanceprobe(h); //擴容完成以後,重新初始化要更新的索引值,盡量保障可以更新成功
}else
if (cellsbusy == 0 && cells == as && //初始化cascellsbusy())
} finally
if (init)
break;
}else
if (casbase(v = base, ((fn == null) ? v + x :
break; // fall back on using base
}
上面的**主要有三個分支:
1. 如果陣列不為空
2. 資料為空,則初始化
3. 前面都更新失敗了,嘗試更新base資料
cellbusy是乙個標示元素,只有當修改cell陣列大小或者插入元素的時候才會修改。分支
二、分支三都很簡單,我們來重點分析一下分支一。
當要更新的位置沒有元素的時候,首先cas標誌位,防止擴容以及插入元素,然後插入資料。如果成功直接返回,否則標示發生了衝突,然後重試。如果對應的位置有元素則更新,如果更新失敗,進行判斷是否陣列的大小已經超過了cpu的核數,如果大於的話,則意味著擴容沒有意義。直接重試。否則進行擴容,擴容完成後,重新設定要更新的位置,盡可能保證下一次更新成功。
我們來看一下如何統計計數。
當計數的時候,將base和各個cell元素裡面的值進行疊加,從而得到計算總數的目的。這裡的問題是在計數的同時如果修改cell元素,有可能導致計數的結果不準確。
longadder在atomiclong的基礎上將單點的更新壓力分散到各個節點,在低併發的時候通過對base的直接更新可以很好的保障和atomiclong的效能基本保持一致,而在高併發的時候通過分散提高了效能。
缺點是longadder在統計的時候如果有併發更新,可能導致統計的資料有誤差。
AtomicLong和LongAdder的區別
atomiclong和longadder的區別 最近在看到不少框架裡面使用到了longadder這個類,而並非atomiclong,很是困惑,於是專門看了longadder的原始碼,總結一下這兩個的區別。就像我們所知道的那樣,atomiclong的原理是依靠底層的cas來保障原子性的更新資料,在要新...
AtomicLong與LongAdder的區別
atomiclong的原理 atomiclong是通過依靠底層的cas來保障原子性的更新資料,在要新增或者減少的時候,會使用死迴圈不斷地cas到特定的值,從而達到更新資料的目的。longadder的原理 longadder是在atomiclong的基礎上將單點更新壓力分散到各個節點,在低併發的時候通...
long和int的區別
short與long兩個限定符的引入可以為我們提供滿足實際需要的不同長度的整形數。int通常代表特定機器中證書的自然長度。short型別通常為16位,long型別通常為32位,int型別可以為16位或32位。各編譯器可以根據硬體特性自主選擇合適的型別長度,但要遵循下列限制 short與int型別至少...