日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

java 并发包之 LongAdder 源码分析

發(fā)布時(shí)間:2023/12/18 编程问答 52 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 并发包之 LongAdder 源码分析 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

?

前些天發(fā)現(xiàn)了一個(gè)巨牛的人工智能學(xué)習(xí)網(wǎng)站,通俗易懂,風(fēng)趣幽默,忍不住分享一下給大家。點(diǎn)擊跳轉(zhuǎn)到教程。

LongAdder是java8中新增的原子類,在多線程環(huán)境中,它比AtomicLong性能要高出不少,特別是寫(xiě)多的場(chǎng)景。

它是怎么實(shí)現(xiàn)的呢?讓我們一起來(lái)學(xué)習(xí)吧。

原理

LongAdder的原理是,在最初無(wú)競(jìng)爭(zhēng)時(shí),只更新base的值,當(dāng)有多線程競(jìng)爭(zhēng)時(shí)通過(guò)分段的思想,讓不同的線程更新不同的段,最后把這些段相加就得到了完整的LongAdder存儲(chǔ)的值。

源碼分析

LongAdder繼承自Striped64抽象類,Striped64中定義了Cell內(nèi)部類和各重要屬性。

主要內(nèi)部類

Cell類使用@sun.misc.Contended注解,說(shuō)明是要避免偽共享的。

使用Unsafe的CAS更新value的值,其中value的值使用volatile修飾,保證可見(jiàn)性。

關(guān)于Unsafe的介紹請(qǐng)查看【死磕 java魔法類之Unsafe解析】。

關(guān)于偽共享的介紹請(qǐng)查看【雜談 什么是偽共享(false sharing)?】。

主要屬性

最初無(wú)競(jìng)爭(zhēng)或有其它線程在創(chuàng)建cells數(shù)組時(shí)使用base更新值,有過(guò)競(jìng)爭(zhēng)時(shí)使用cells更新值。

最初無(wú)競(jìng)爭(zhēng)是指一開(kāi)始沒(méi)有線程之間的競(jìng)爭(zhēng),但也有可能是多線程在操作,只是這些線程沒(méi)有同時(shí)去更新base的值。

有過(guò)競(jìng)爭(zhēng)是指只要出現(xiàn)過(guò)競(jìng)爭(zhēng)不管后面有沒(méi)有競(jìng)爭(zhēng)都使用cells更新值,規(guī)則是不同的線程hash到不同的cell上去更新,減少競(jìng)爭(zhēng)。

add(x)方法

add(x)方法是LongAdder的主要方法,使用它可以使LongAdder中存儲(chǔ)的值增加x,x可為正可為負(fù)。


(1)最初無(wú)競(jìng)爭(zhēng)時(shí)只更新base;

(2)直到更新base失敗時(shí),創(chuàng)建cells數(shù)組;

(3)當(dāng)多個(gè)線程競(jìng)爭(zhēng)同一個(gè)Cell比較激烈時(shí),可能要擴(kuò)容;

sum()方法

sum()方法

可以看到sum()方法是把base和所有段的值相加得到,那么,這里有一個(gè)問(wèn)題,如果前面已經(jīng)累加到sum上的Cell的value有修改,不是就沒(méi)法計(jì)算到了么?

答案確實(shí)如此,所以LongAdder可以說(shuō)不是強(qiáng)一致性的,它是最終一致性的。

LongAdder VS AtomicLong

當(dāng)只有一個(gè)線程的時(shí)候,AtomicLong反而性能更高,隨著線程越來(lái)越多,AtomicLong的性能急劇下降,而LongAdder的性能影響很小。

總結(jié)

(1)LongAdder通過(guò)base和cells數(shù)組來(lái)存儲(chǔ)值;

(2)不同的線程會(huì)hash到不同的cell上去更新,減少了競(jìng)爭(zhēng);

(3)LongAdder的性能非常高,最終會(huì)達(dá)到一種無(wú)競(jìng)爭(zhēng)的狀態(tài);

彩蛋

在longAccumulate()方法中有個(gè)條件是?n>=NCPU就不會(huì)走到擴(kuò)容邏輯了,而n是2的倍數(shù),那是不是代表cells數(shù)組最大只能達(dá)到大于等于NCPU的最小2次方?

答案是明確的。因?yàn)橥粋€(gè)CPU核心同時(shí)只會(huì)運(yùn)行一個(gè)線程,而更新失敗了說(shuō)明有兩個(gè)不同的核心更新了同一個(gè)Cell,這時(shí)會(huì)重新設(shè)置更新失敗的那個(gè)線程的probe值,這樣下一次它所在的Cell很大概率會(huì)發(fā)生改變,如果運(yùn)行的時(shí)間足夠長(zhǎng),最終會(huì)出現(xiàn)同一個(gè)核心的所有線程都會(huì)hash到同一個(gè)Cell(大概率,但不一定全在一個(gè)Cell上)上去更新,所以,這里cells數(shù)組中長(zhǎng)度并不需要太長(zhǎng),達(dá)到CPU核心數(shù)足夠了。

比如,筆者的電腦是8核的,所以這里cells的數(shù)組最大只會(huì)到8,達(dá)到8就不會(huì)擴(kuò)容了。

總結(jié)

以上是生活随笔為你收集整理的java 并发包之 LongAdder 源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。