Java 內(nèi)存模式 HB法則

Java內(nèi)存模型 HB法則

概述

  • HB 7法則:volatile帽揪、start線程開(kāi)始戏罢、join線程結(jié)束屋谭、lock鎖釋放之后、finalize對(duì)象銷毀龟糕,時(shí)間先后桐磁、傳遞性
  • java內(nèi)存模型:每個(gè)線程操作數(shù)據(jù)是把對(duì)象拷貝到本地內(nèi)存然進(jìn)行操作,最后寫(xiě)回到主內(nèi)存當(dāng)中讲岁,不同線程之間不可見(jiàn)
  • JMM為了防止重排序引發(fā)問(wèn)題我擂,保證了happens-before法則,這些法則是不會(huì)被重排序打亂的
  • java的原子性:一個(gè)操作是原子操作缓艳,那么我們稱它具有原子性校摩,JDK1.5后再JUC包下有AotmicInteger來(lái)簡(jiǎn)化并發(fā)的原子操作,讀取 操作 復(fù)查 寫(xiě)入的一個(gè)過(guò)程阶淘。多了一個(gè)可見(jiàn)性的復(fù)查過(guò)程避免線程不安全衙吩。unsafe類提供本地方法直接操作內(nèi)存,從硬件方面實(shí)現(xiàn)原子性溪窒。

happens-before原則:

7個(gè)場(chǎng)景總結(jié):

  • 子線程.start()
  • 子線程.join()
  • volatile
  • lock
  • 傳遞性
  • 初始化
  • 單一線程前后性
  1. Each action in a thread happens-before every subsequent action in that thread.
    在一個(gè)線程當(dāng)中 先執(zhí)行的代碼結(jié)果 對(duì)隨后進(jìn)行的代碼可見(jiàn)坤塞。(廢話,一個(gè)線程公用一個(gè)本地緩存)

  2. An unlock on a monitor happens-before every subsequent lock on that monitor
    對(duì)一個(gè)監(jiān)視器進(jìn)行解鎖時(shí)的所有操作澈蚌,對(duì)下一個(gè)鎖的代碼是可見(jiàn)的摹芙,比如在線程A中改了共有變量n的值,現(xiàn)在線程B獲取了相同的鎖宛瞄,它是可以看見(jiàn)改變后n的值的浮禾。

  3. A write to a volatile field happens-before every subsequent read of that volatile.
    A改了一個(gè)volatile的值,對(duì)接下來(lái)的所有的讀取該變量值的線程可見(jiàn)

  4. A可見(jiàn)于B B可見(jiàn)于C,那么A的所有操作也可見(jiàn)于C

  5. start規(guī)則:如果線程A執(zhí)行線程B的start方法盈电,那么線程A的ThreadB.start()happens-before于線程B的任意操作
    A執(zhí)行的操作之后再啟動(dòng)B線程蝴簇,則A線程之前改過(guò)的值對(duì)B可見(jiàn)

static int index=1;
index++挣轨;
new Thread(new runnable(){
    public void run(){
        system.out.println(index);
    }
}).start();
  1. join規(guī)則:如果線程A執(zhí)行線程B的join方法军熏,那么線程B的任意操作happens-before于線程A從TreadB.join()方法成功返回
main(){
    t1.start()
    t1.join()
    ti修改過(guò)的變量對(duì)main線程可見(jiàn)
}
  1. 對(duì)象終結(jié)規(guī)則:一個(gè)對(duì)象的初始化完成先行發(fā)生于他的finalize()方法的開(kāi)始;

可見(jiàn)性問(wèn)題

基于java的內(nèi)存模型卷扮,不同線程操作相同變量的時(shí)候荡澎,因?yàn)榫€程之間不可見(jiàn),會(huì)導(dǎo)致可見(jiàn)性問(wèn)題晤锹。

  1. 舉例:
    主內(nèi)存中有變量count=100(比如某個(gè)對(duì)象的成員變量為count是100)摩幔,現(xiàn)在多個(gè)線程去消費(fèi)這個(gè)對(duì)象的count。
    線程A讀取count=100鞭铆,進(jìn)行了count消費(fèi)一個(gè)或衡,修改本地內(nèi)存為99,這個(gè)時(shí)候并不會(huì)直接寫(xiě)回到主內(nèi)存當(dāng)中车遂,此時(shí)線程B去主內(nèi)存中讀取并消費(fèi)count封断,最后線程A結(jié)束,寫(xiě)回count為99到主內(nèi)存舶担,線程B結(jié)束的時(shí)候坡疼,也寫(xiě)回99到主內(nèi)存,因?yàn)榭梢?jiàn)性問(wèn)題衣陶,導(dǎo)致count被消費(fèi)2次柄瑰,但是總量只減少了1。

  2. 解決方案(volatile關(guān)鍵字剪况、synchronized教沾、final)

  • synchronized可以保證線程安全,但是效率低
  • volatile不能保證線程安全译断,但是可以緩解線程不可見(jiàn)的問(wèn)題授翻,比如A消費(fèi)了count從100到99的時(shí)候,會(huì)立刻把count寫(xiě)回到主內(nèi)存孙咪,如果B線程這個(gè)時(shí)候去取count這個(gè)對(duì)象藏姐,取到的就是99,而不是100该贾。
  • final關(guān)鍵字編譯的時(shí)候就必須賦值,相當(dāng)于常量捌臊,可以避免線程安全問(wèn)題杨蛋,但是運(yùn)用的場(chǎng)景有限,一旦賦值不允許修改。

java重排序:

  1. 編譯期:編譯器在編譯的時(shí)候可能會(huì)打亂沒(méi)有依賴關(guān)系的代碼的編譯順序

  2. CPU執(zhí)行指令:執(zhí)行不能保證編譯的順序逞力,且有時(shí)候會(huì)并發(fā)的執(zhí)行

  3. 寫(xiě)入主內(nèi)存時(shí)期:不能保證寄存器寫(xiě)會(huì)主內(nèi)存的順序是按照代碼寫(xiě)的那樣

  4. 證明java的重排序
    注意只有當(dāng)多個(gè)線程的時(shí)候才會(huì)出現(xiàn)這種情況曙寡,單線程一定不會(huì)出現(xiàn)這種情況,因?yàn)榇嬖诰€程切換的時(shí)候寇荧,寄存器未寫(xiě)入到主內(nèi)存當(dāng)中举庶,才會(huì)這樣。

循環(huán)輸出的話揩抡,會(huì)出現(xiàn) a:1,x:0,b:1),y:0) 的情況的出現(xiàn)户侥,可以證明。
因?yàn)椴淮嬖谥嘏判虻脑挘?/p>

  • 如果先執(zhí)行one線程峦嗤,則a=1蕊唐,y一定等于1;
  • 如果先執(zhí)行other線程的話烁设,則b=1替梨,導(dǎo)致x一定等于1
  • 所以不存在 x和y同時(shí)為0的情況發(fā)生
    除非重排序,先執(zhí)行x=b=0的時(shí)候装黑,再切換線程y=a=0副瀑,的時(shí)候才會(huì)出現(xiàn)這種情況
public class Test {
    static int x = 0, y = 0;
    static int a = 0, b = 0;

    public static void main(String[] args) throws InterruptedException {
        while(true){
            x=y=a=b=0;
            test();
        }
    }
    
    public static void test() throws InterruptedException{
        Thread one = new Thread(new Runnable() {
            public void run() {
                a = 1;
                x = b;
            }
        });

        Thread other = new Thread(new Runnable() {
            public void run() {
                b = 1;
                y = a;
            }
        });
        one.start();other.start();
        one.join();other.join();
        if(x+y==0){
            System.out.println("a:" + a +",x:" + x + ",b:" + b +")"+ ",y:" + y +")");
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市恋谭,隨后出現(xiàn)的幾起案子糠睡,更是在濱河造成了極大的恐慌,老刑警劉巖箕别,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件铜幽,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡串稀,警方通過(guò)查閱死者的電腦和手機(jī)除抛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)母截,“玉大人到忽,你說(shuō)我怎么就攤上這事∏蹇埽” “怎么了喘漏?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)华烟。 經(jīng)常有香客問(wèn)我翩迈,道長(zhǎng),這世上最難降的妖魔是什么盔夜? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任负饲,我火速辦了婚禮堤魁,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘返十。我一直安慰自己妥泉,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布洞坑。 她就那樣靜靜地躺著盲链,像睡著了一般。 火紅的嫁衣襯著肌膚如雪迟杂。 梳的紋絲不亂的頭發(fā)上刽沾,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天,我揣著相機(jī)與錄音逢慌,去河邊找鬼悠轩。 笑死,一個(gè)胖子當(dāng)著我的面吹牛攻泼,可吹牛的內(nèi)容都是我干的火架。 我是一名探鬼主播,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼忙菠,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼何鸡!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起牛欢,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤骡男,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后傍睹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體隔盛,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年拾稳,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吮炕。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡访得,死狀恐怖龙亲,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悍抑,我是刑警寧澤鳄炉,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布,位于F島的核電站搜骡,受9級(jí)特大地震影響拂盯,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜记靡,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一磕仅、第九天 我趴在偏房一處隱蔽的房頂上張望珊豹。 院中可真熱鬧,春花似錦榕订、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至轿腺,卻和暖如春两嘴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背族壳。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工憔辫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人仿荆。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓贰您,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親拢操。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锦亦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

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

  • Java的并發(fā)采用的是共享內(nèi)存模型(而非消息傳遞模型),線程之間共享程序的公共狀態(tài)令境,線程之間通過(guò)寫(xiě)-讀內(nèi)存中的公共...
    阿斯蒂芬2閱讀 482評(píng)論 0 1
  • 1.Java內(nèi)存模型的基礎(chǔ) ①并發(fā)編程模型的兩個(gè)關(guān)鍵問(wèn)題 線程之間如何通信杠园、線程之間如何同步 通信是指線程之間以何...
    加夕閱讀 742評(píng)論 0 1
  • 第2章 java并發(fā)機(jī)制的底層實(shí)現(xiàn)原理 Java中所使用的并發(fā)機(jī)制依賴于JVM的實(shí)現(xiàn)和CPU的指令。 2.1 vo...
    kennethan閱讀 1,432評(píng)論 0 2
  • 目錄: 1. 指令重排 2. 順序一致性 3. volatile 4. final 1.指令重排 要了解指令重排舔庶,...
    西部小籠包閱讀 756評(píng)論 0 1
  • 并發(fā)系列的文章都是根據(jù)閱讀《Java 并發(fā)編程的藝術(shù)》這本書(shū)總結(jié)而來(lái)抛蚁,想更深入學(xué)習(xí)的同學(xué)可以自行購(gòu)買(mǎi)此書(shū)進(jìn)行學(xué)習(xí)。...
    小之丶閱讀 1,052評(píng)論 1 7