JDK8中新增原子性操作類LongAdder,LongAdder類是LongAccumulator的一個特例,LongAccumulator提供了比LongAdder更強大的功能,只需要構造LongAccumulator時候傳入自定義雙面運算器就OK,后者則內置累加的規(guī)則。
前言
本文主要給大家介紹了關于JDK8新增的原子性操作類LongAdder的相關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹:
LongAdder簡單介紹
LongAdder類似于AtomicLong是原子性遞增或者遞減類,AtomicLong已經通過CAS提供了非阻塞的原子性操作,相比使用阻塞算法的同步器來說性能已經很好了,但是JDK開發(fā)組并不滿足,因為在非常高的并發(fā)請求下AtomicLong的性能不能讓他們接受,雖然AtomicLong使用CAS但是CAS失敗后還是通過無限循環(huán)的自旋鎖不斷嘗試的
在高并發(fā)下N多線程同時去操作一個變量會造成大量線程CAS失敗然后處于自旋狀態(tài),這大大浪費了cpu資源,降低了并發(fā)性。那么既然AtomicLong性能由于過多線程同時去競爭一個變量的更新而降低的,那么如果把一個變量分解為多個變量,讓同樣多的線程去競爭多個資源那么性能問題不就解決了?是的,JDK8提供的LongAdder就是這個思路。下面通過圖形來標示兩者不同。
如圖AtomicLong是多個線程同時競爭同一個變量。
如圖LongAdder則是內部維護多個變量,每個變量初始化都0,在同等并發(fā)量的情況下,爭奪單個變量的線程量會減少這是變相的減少了爭奪共享資源的并發(fā)量,另外多個線程在爭奪同一個原子變量時候如果失敗并不是自旋CAS重試,而是嘗試獲取其他原子變量的鎖,最后獲取當前值時候是把所有變量的值累加后返回的。
LongAdder維護了一個延遲初始化的原子性更新數(shù)組和一個基值變量base.數(shù)組的大小保持是2的N次方大小,數(shù)組表的下標使用每個線程的hashcode值的掩碼表示,數(shù)組里面的變量實體是Cell類型,Cell類型是AtomicLong的一個改進,用來減少緩存的爭用,對于大多數(shù)原子操作字節(jié)填充是浪費的,因為原子性操作都是無規(guī)律的分散在內存中進行的,多個原子性操作彼此之間是沒有接觸的,但是原子性數(shù)組元素彼此相鄰存放將能經常共享緩存行,所以這在性能上是一個提升。
另外由于Cells占用內存是相對比較大的,所以一開始并不創(chuàng)建,而是在需要時候在創(chuàng)建,也就是惰性加載,當一開始沒有空間時候,所有的更新都是操作base變量,
自旋鎖cellsBusy用來初始化和擴容數(shù)組表使用,這里沒有必要用阻塞鎖,當一次線程發(fā)現(xiàn)當前下標的元素獲取鎖失敗后,會嘗試獲取其他下表的元素的鎖。更詳細的說明敬請期待 Java并發(fā)編程基礎之并發(fā)包源碼剖析 一書的出版
- PC官方版
- 安卓官方手機版
- IOS官方手機版