偽共享(False Sharing)和緩存行(Cache Line) 大雜燴

前言

在上篇介紹LongAdder的文章中冤馏,我們最后留下了一個(gè)問(wèn)題,為什么Cell中要插入很多個(gè)實(shí)際上并沒有使用的Long變量寄啼?這個(gè)問(wèn)題就得從False Sharing和Cache line開始說(shuō)起逮光。首先我們得知道Cache line是啥,推薦兩篇文章:文章1文章2墩划。

科普False Sharing

在有了Cache line基礎(chǔ)之后涕刚,讓我們看看一篇介紹False Sharing的文章,這篇文章介紹了False Sharing以及簡(jiǎn)單說(shuō)明了java8搞出的@Contented乙帮,翻譯如下:

——————————————翻譯start———————————————
java 8中引入了一個(gè)新注解 @Contented,主要是用來(lái)減少“False sharing”杜漠,這篇文章主要講述了@Contented,解釋 了"False sharing"如何成為了性能殺手蚣旱。

"Cache Line"簡(jiǎn)介

CPU不是按單個(gè)bytes來(lái)讀取內(nèi)存數(shù)據(jù)的碑幅,而是以“塊數(shù)據(jù)”的形式,每塊的大小通常為64bytes塞绿,這些“塊”被成為“Cache Line”(這種說(shuō)法其實(shí)很不太正確沟涨,關(guān)于Cache Line的知識(shí)請(qǐng)參考文末的參考鏈接)

如果有兩個(gè)線程(Thread1 和 Thread2)同時(shí)修改一個(gè)volatile數(shù)據(jù),把這個(gè)數(shù)據(jù)記為'x':

volatile long x;

如果線程1打算更改x的值异吻,而線程2準(zhǔn)備讀裙啊:

Thread1:x=3;
Thread2: System.out.println(x);

由于x值被更新了,所以x值需要在線程1和線程2之間傳遞(從線程1到線程2)诀浪,x的變更會(huì)引起整塊64bytes被交換棋返,因?yàn)閏pu核之間以cache lines的形式交換數(shù)據(jù)(cache lines的大小一般為64bytes)。有可能線程1和線程2在同一個(gè)核心里處理雷猪,但是在這個(gè)簡(jiǎn)單的例子中我們假設(shè)每個(gè)線程在不同的核中被處理睛竣。

我們知道long values的內(nèi)存長(zhǎng)度為8bytes,在我們例子中"Cache Line"為64bytes求摇,所以一個(gè)cache line可以存儲(chǔ)8個(gè)long型變量射沟,在cache line中已經(jīng)存儲(chǔ)了一個(gè)long型變量x殊者,我們假設(shè)cache line中剩余的空間用來(lái)存儲(chǔ)了7個(gè)long型變量,例如從v1到v7
x,v1,v2,v3,v4,v5,v6,v7

False Sharing

一個(gè)cache lien可以被多個(gè)不同的線程所使用验夯。如果有其他線程修改了v2的值猖吴,線程1和線程2將會(huì)強(qiáng)制重新加載cache line。你可以會(huì)疑惑我們只是修改了v2的值不應(yīng)該會(huì)影響其他變量挥转,為啥線程1和線程2需要重新加載cache line呢海蔽。然后,即使對(duì)于多個(gè)線程來(lái)說(shuō)這些更新操作是邏輯獨(dú)立的绑谣,但是一致性的保持是以cache line為基礎(chǔ)的党窜,而不是以單個(gè)獨(dú)立的元素。這種明顯沒有必要的共享數(shù)據(jù)的方式被稱作“False sharing”.

Padding

為了獲取一個(gè)cache line域仇,核心需要執(zhí)行幾百個(gè)指令刑然。

如果核心需要等待一個(gè)cache line重新加載,核心將會(huì)停止做其他事情暇务,這種現(xiàn)象被稱為"Stall".Stalls可以通過(guò)減少“False Sharing”,一個(gè)減少"false sharing"的技巧是填充數(shù)據(jù)結(jié)構(gòu)泼掠,使得線程操作的變量落入到不同的cache line中。

下面是一個(gè)填充了的數(shù)據(jù)結(jié)構(gòu)的例子垦细,嘗試著把x和v1放入到不同的cache line中

public class FalseSharingWithPadding { 
 
    public volatile long x; 
    public volatile long p2;   // padding 
    public volatile long p3;   // padding 
    public volatile long p4;   // padding 
    public volatile long p5;   // padding 
    public volatile long p6;   // padding 
    public volatile long p7;   // padding 
    public volatile long p8;   // padding 
    public volatile long v1; 
}

在你準(zhǔn)備填充你的所有數(shù)據(jù)結(jié)構(gòu)之前择镇,你必須了解jvm會(huì)減少或者重排序沒有使用的字段,因此可能會(huì)重新引入“false sharing”括改。因此對(duì)象會(huì)在堆中的位置是沒有辦法保證的腻豌。

為了減少未使用的填充字段被優(yōu)化掉的機(jī)會(huì),將這些字段設(shè)置成為volatile會(huì)很有幫助嘱能。對(duì)于填充的建議是你只需要在高度競(jìng)爭(zhēng)的并發(fā)類上使用填充吝梅,并且在你的目標(biāo)架構(gòu)上測(cè)試使用有很大提升之后采用填充。最好的方式是做10000玄幻迭代惹骂,消除JVM的實(shí)時(shí)優(yōu)化的影響苏携。

java8 和 @Contended

比起引入填充字段,一個(gè)更加簡(jiǎn)單有效的方式是在你需要避免“false sharing”的字段上標(biāo)記注解对粪,這可以暗示虛擬機(jī)“這個(gè)字段可以分離到不同的cache line中”右冻,這是JEP 142的目標(biāo)。

JEP引入了 @Contended 注解著拭。

public class Point { 
    int x;
    @Contended
    int y; 
} 

以上代碼使得x和y都在不同的cache line中纱扭。@Contended 使得y字段遠(yuǎn)離了對(duì)象頭部分。

————————————————翻譯end——————————————————

False Sharing在java6/7中

如何避免False Sharing在java 6 7 8 中有不同的實(shí)現(xiàn)方式儡遮, 這篇文章對(duì)比了在6/7/8下面的實(shí)現(xiàn)乳蛾。國(guó)內(nèi)的多篇關(guān)于偽共享的文章基本都來(lái)源于Martin的兩篇博客。
博客1博客2,博客1主要介紹了什么是False Sharing以及怎么避免False Sharing(在java6的環(huán)境下)屡久,我在看完這篇文文章后使用他的testbench進(jìn)行了測(cè)試忆首,得到的結(jié)果是在java6環(huán)境下,使用6個(gè)long變量進(jìn)行填充是不一定能完全避免false sharing被环,但是我使用了

public final static class VolatileLong {
        public volatile long q1, q2, q3, q4, q5, q6, q7;
        public volatile long value = 0L;
        public volatile long p1, p2, p3, p4, p5, p6, p7;
    }

這種方式得到的結(jié)果是完全能夠避免false sharing,我以此郵件了作者M(jìn)artin Thompson說(shuō)明此問(wèn)題详幽,Martin Thompson很快回了郵件附上了博客2的鏈接問(wèn)我是否看過(guò)博客2的內(nèi)容筛欢,我讀過(guò)之后發(fā)現(xiàn)博客2寫的是在java7的環(huán)境下虛擬機(jī)層面會(huì)對(duì)沒有使用的變量進(jìn)行優(yōu)化,所以會(huì)導(dǎo)致false sharing的問(wèn)題唇聘,我覺得這是一個(gè)新的問(wèn)題并不能解釋我在java6環(huán)境下發(fā)生的現(xiàn)象版姑。在java7環(huán)境下要使用填充的方式避免false sharing需要繞很多彎彎而且并不一定能夠達(dá)到效果。所以我覺得我們不能通過(guò)這種“黑科技”解決false sharing的問(wèn)題迟郎,包括Martin Thompson的很多人都希望jvm的開發(fā)團(tuán)隊(duì)能夠搞出一套機(jī)制能夠支持在上層決定多個(gè)字段是否可以出現(xiàn)在同一個(gè)cache line剥险,所以應(yīng)大家的響應(yīng),在java8中宪肖,jvm團(tuán)隊(duì)搞出了@Contended注解來(lái)進(jìn)行支持

java8中的@Contended

關(guān)于@Contended的用法表制,我們可以參考一個(gè)鏈接,這是jvm團(tuán)隊(duì)內(nèi)部關(guān)于JEP-142實(shí)現(xiàn)的一個(gè)郵件回復(fù)控乾,雖然可能和具體實(shí)現(xiàn)有所差別么介,但是參考價(jià)值很大。所以LongAdder在java8中的實(shí)現(xiàn)已經(jīng)采用了@Contended

總結(jié)

這是一個(gè)關(guān)于false sharing的參考文檔的大雜燴蜕衡,沒啥自己的理解壤短。我的建議就是要避免false sharing就在java8環(huán)境下使用@Contended。下篇終于要介紹HystrixRollingNumber了

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末慨仿,一起剝皮案震驚了整個(gè)濱河市久脯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌镰吆,老刑警劉巖帘撰,帶你破解...
    沈念sama閱讀 211,194評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異鼎姊,居然都是意外死亡骡和,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,058評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門相寇,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)慰于,“玉大人,你說(shuō)我怎么就攤上這事唤衫∑旁” “怎么了?”我有些...
    開封第一講書人閱讀 156,780評(píng)論 0 346
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)休里。 經(jīng)常有香客問(wèn)我蛆挫,道長(zhǎng),這世上最難降的妖魔是什么妙黍? 我笑而不...
    開封第一講書人閱讀 56,388評(píng)論 1 283
  • 正文 為了忘掉前任悴侵,我火速辦了婚禮,結(jié)果婚禮上拭嫁,老公的妹妹穿的比我還像新娘可免。我一直安慰自己,他們只是感情好做粤,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,430評(píng)論 5 384
  • 文/花漫 我一把揭開白布浇借。 她就那樣靜靜地躺著,像睡著了一般怕品。 火紅的嫁衣襯著肌膚如雪妇垢。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,764評(píng)論 1 290
  • 那天肉康,我揣著相機(jī)與錄音闯估,去河邊找鬼。 笑死迎罗,一個(gè)胖子當(dāng)著我的面吹牛睬愤,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播纹安,決...
    沈念sama閱讀 38,907評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼尤辱,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了厢岂?” 一聲冷哼從身側(cè)響起光督,我...
    開封第一講書人閱讀 37,679評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎塔粒,沒想到半個(gè)月后结借,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,122評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡卒茬,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,459評(píng)論 2 325
  • 正文 我和宋清朗相戀三年船老,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片圃酵。...
    茶點(diǎn)故事閱讀 38,605評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡柳畔,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出郭赐,到底是詐尸還是另有隱情薪韩,我是刑警寧澤,帶...
    沈念sama閱讀 34,270評(píng)論 4 329
  • 正文 年R本政府宣布,位于F島的核電站俘陷,受9級(jí)特大地震影響罗捎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜拉盾,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,867評(píng)論 3 312
  • 文/蒙蒙 一桨菜、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧盾剩,春花似錦雷激、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,734評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)承桥。三九已至驻粟,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間凶异,已是汗流浹背蜀撑。 一陣腳步聲響...
    開封第一講書人閱讀 31,961評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留剩彬,地道東北人酷麦。 一個(gè)月前我還...
    沈念sama閱讀 46,297評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像喉恋,于是被迫代替她去往敵國(guó)和親沃饶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,472評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理轻黑,服務(wù)發(fā)現(xiàn)糊肤,斷路器,智...
    卡卡羅2017閱讀 134,629評(píng)論 18 139
  • Java8張圖 11氓鄙、字符串不變性 12馆揉、equals()方法、hashCode()方法的區(qū)別 13抖拦、...
    Miley_MOJIE閱讀 3,696評(píng)論 0 11
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評(píng)論 6 342
  • 忙時(shí)專注升酣,閑時(shí)懈怠,許久未更周結(jié)态罪,甚慚愧噩茄。遂直接分享整個(gè)9月動(dòng)態(tài)。 Part 1 Projects at wor...
    Estelle0331閱讀 403評(píng)論 0 1
  • 默默地我低頭數(shù)著四腳走過(guò)的足印肩上拉著沉重的犁不曾回頭望向背后被我汗水浸濕的土地 悄悄地我抬頭凝視遠(yuǎn)方的漫無(wú)邊際四...
    西門可情閱讀 408評(píng)論 0 2