JDK8中新增的原子性操作類(lèi)LongAdder詳解
前言
本文主要給大家介紹了關(guān)于JDK8新增的原子性操作類(lèi)LongAdder的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),下面話(huà)不多說(shuō)了,來(lái)一起看看詳細(xì)的介紹:
LongAdder簡(jiǎn)單介紹
LongAdder類(lèi)似于A(yíng)tomicLong是原子性遞增或者遞減類(lèi),AtomicLong已經(jīng)通過(guò)CAS提供了非阻塞的原子性操作,相比使用阻塞算法的同步器來(lái)說(shuō)性能已經(jīng)很好了,但是JDK開(kāi)發(fā)組并不滿(mǎn)足,因?yàn)樵诜浅8叩牟l(fā)請(qǐng)求下AtomicLong的性能不能讓他們接受,雖然AtomicLong使用CAS但是CAS失敗后還是通過(guò)無(wú)限循環(huán)的自旋鎖不斷嘗試的
public final long incrementAndGet() { for (;;) { long current = get(); long next = current + 1; if (compareAndSet(current, next)) return next; } }
在高并發(fā)下N多線(xiàn)程同時(shí)去操作一個(gè)變量會(huì)造成大量線(xiàn)程CAS失敗然后處于自旋狀態(tài),這大大浪費(fèi)了cpu資源,降低了并發(fā)性。那么既然AtomicLong性能由于過(guò)多線(xiàn)程同時(shí)去競(jìng)爭(zhēng)一個(gè)變量的更新而降低的,那么如果把一個(gè)變量分解為多個(gè)變量,讓同樣多的線(xiàn)程去競(jìng)爭(zhēng)多個(gè)資源那么性能問(wèn)題不就解決了?是的,JDK8提供的LongAdder就是這個(gè)思路。下面通過(guò)圖形來(lái)標(biāo)示兩者不同。
如圖AtomicLong是多個(gè)線(xiàn)程同時(shí)競(jìng)爭(zhēng)同一個(gè)變量。
如圖LongAdder則是內(nèi)部維護(hù)多個(gè)變量,每個(gè)變量初始化都0,在同等并發(fā)量的情況下,爭(zhēng)奪單個(gè)變量的線(xiàn)程量會(huì)減少這是變相的減少了爭(zhēng)奪共享資源的并發(fā)量,另外多個(gè)線(xiàn)程在爭(zhēng)奪同一個(gè)原子變量時(shí)候如果失敗并不是自旋CAS重試,而是嘗試獲取其他原子變量的鎖,最后獲取當(dāng)前值時(shí)候是把所有變量的值累加后返回的。
LongAdder維護(hù)了一個(gè)延遲初始化的原子性更新數(shù)組和一個(gè)基值變量base.數(shù)組的大小保持是2的N次方大小,數(shù)組表的下標(biāo)使用每個(gè)線(xiàn)程的hashcode值的掩碼表示,數(shù)組里面的變量實(shí)體是Cell類(lèi)型,Cell類(lèi)型是AtomicLong的一個(gè)改進(jìn),用來(lái)減少緩存的爭(zhēng)用,對(duì)于大多數(shù)原子操作字節(jié)填充是浪費(fèi)的,因?yàn)樵有圆僮鞫际菬o(wú)規(guī)律的分散在內(nèi)存中進(jìn)行的,多個(gè)原子性操作彼此之間是沒(méi)有接觸的,但是原子性數(shù)組元素彼此相鄰存放將能經(jīng)常共享緩存行,所以這在性能上是一個(gè)提升。
另外由于Cells占用內(nèi)存是相對(duì)比較大的,所以一開(kāi)始并不創(chuàng)建,而是在需要時(shí)候在創(chuàng)建,也就是惰性加載,當(dāng)一開(kāi)始沒(méi)有空間時(shí)候,所有的更新都是操作base變量,
自旋鎖cellsBusy用來(lái)初始化和擴(kuò)容數(shù)組表使用,這里沒(méi)有必要用阻塞鎖,當(dāng)一次線(xiàn)程發(fā)現(xiàn)當(dāng)前下標(biāo)的元素獲取鎖失敗后,會(huì)嘗試獲取其他下表的元素的鎖。更詳細(xì)的說(shuō)明敬請(qǐng)期待 Java并發(fā)編程基礎(chǔ)之并發(fā)包源碼剖析 一書(shū)的出版
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
SpringBoot統(tǒng)一響應(yīng)和統(tǒng)一異常處理詳解
在開(kāi)發(fā)Spring Boot應(yīng)用時(shí),處理響應(yīng)結(jié)果和異常的方式對(duì)項(xiàng)目的可維護(hù)性、可擴(kuò)展性和團(tuán)隊(duì)協(xié)作有著至關(guān)重要的影響,統(tǒng)一結(jié)果返回和統(tǒng)一異常處理是提升項(xiàng)目質(zhì)量的關(guān)鍵策略之一,所以本文給大家詳細(xì)介紹了SpringBoot統(tǒng)一響應(yīng)和統(tǒng)一異常處理,需要的朋友可以參考下2024-08-08如何解決freemarker靜態(tài)化生成html頁(yè)面亂碼的問(wèn)題
這篇文章主要介紹了如何解決freemarker靜態(tài)化生成html頁(yè)面亂碼的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01Java基于JDBC連接數(shù)據(jù)庫(kù)及顯示數(shù)據(jù)操作示例
這篇文章主要介紹了Java基于JDBC連接數(shù)據(jù)庫(kù)及顯示數(shù)據(jù)操作,結(jié)合實(shí)例形式分析了Java使用jdbc進(jìn)行mysql數(shù)據(jù)庫(kù)連接與數(shù)據(jù)讀取、顯示等相關(guān)操作技巧,需要的朋友可以參考下2018-06-06使用java實(shí)現(xiàn)telnet-client工具分享
這篇文章主要介紹了使用java實(shí)現(xiàn)telnet-client工具,需要的朋友可以參考下2014-03-03Java對(duì)象簡(jiǎn)單實(shí)用案例之計(jì)算器實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Java對(duì)象簡(jiǎn)單實(shí)用案例之計(jì)算器實(shí)現(xiàn)代碼2016-11-11