java 8大happen-before原則超全面詳解

再來重復下八大原則:

  • 單線程happen-before原則:在同一個線程中坑夯,書寫在前面的操作happen-before后面的操作岖寞。
  • 鎖的happen-before原則:同一個鎖的unlock操作happen-before此鎖的lock操作。
  • volatile的happen-before原則:對一個volatile變量的寫操作happen-before對此變量的任意操作(當然也包括寫操作了)柜蜈。
  • happen-before的傳遞性原則:如果A操作 happen-before B操作仗谆,B操作happen-before C操作指巡,那么A操作happen-before C操作。
  • 線程啟動的happen-before原則:同一個線程的start方法happen-before此線程的其它方法隶垮。
  • 線程中斷的happen-before原則:對線程interrupt方法的調用happen-before被中斷線程的檢測到中斷發(fā)送的代碼藻雪。
  • 線程終結的happen-before原則:線程中的所有操作都happen-before線程的終止檢測证杭。
  • 對象創(chuàng)建的happen-before原則:一個對象的初始化完成先于他的finalize方法調用扣孟。

首先在看本文前,最好先看下《java并發(fā)編程實戰(zhàn)》之java內存模型這篇文章粗蔚,對java內存模型有個了解蹋偏。
happen-before 在這里不能理解成在什么之前發(fā)生便斥,它和時間沒有任何關系。個人感覺解釋成“生效可見于” 更準確威始。下面通過對這八個原則詳細解釋來加深對“生效可見于”的理解枢纠。


在同一個線程中,書寫在前面的操作happen-before后面的操作: 好多文章把這理解成書寫在前面先發(fā)生于書寫在后面的代碼黎棠,但是指令重排序晋渺,確實可以讓書寫在后面的代碼先于書寫在前面的代碼發(fā)生。這是里把happen-before 理解成“先于什么發(fā)生”脓斩,其實happen-beofre在這里沒有任何時間上的含義木西。比如下面的代碼:

int a = 3;      //1
int b = a + 1; //2

這里 //2 對b賦值的操作會用到變量a,那么java的“單線程happen-before原則”就保證 //2的中的a的值一定是3随静,而不是0八千,5,等其他亂七八糟的值,因為//1 書寫在//2前面, //1對變量a的賦值操作對//2一定可見挪挤。因為//2 中有用到//1中的變量a叼丑,再加上java內存模型提供了“單線程happen-before原則”,所以java虛擬機不許可操作系統(tǒng)對//1 //2 操作進行指令重排序扛门,即不可能有//2 在//1之前發(fā)生。但是對于下面的代碼:

int a = 3;
int b = 4;

兩個語句直接沒有依賴關系纵寝,所以指令重排序可能發(fā)生论寨,即對b的賦值可能先于對a的賦值。


同一個鎖的unlock操作happen-beofre此鎖的lock操作: 話不多說直接看下面的代碼:

public class A {
   public int var;

   private static A a = new A();

   private A(){}

   public static A getInstance(){
       return a;
   }

   public synchronized void method1(){
       var = 3;
   }

   public synchronized void method2(){
       int b = var;
   }

   public void method3(){
       synchronized(new A()){ //注意這里和method1 method2 用的可不是同一個鎖哦
           var = 4;
       }
   }
}
//線程1執(zhí)行的代碼:
A.getInstance().method1(); 
//線程2執(zhí)行的代碼:
A.getInstance().method2(); 
//線程3執(zhí)行的代碼:
A.getInstance().method3();

如果某個時刻執(zhí)行完“線程1” 馬上執(zhí)行“線程2”爽茴,因為“線程1”執(zhí)行A類的method1方法后肯定要釋放鎖葬凳,“線程2”在執(zhí)行A類的method2方法前要先拿到鎖,符合“鎖的happen-before原則”室奏,那么在“線程2”method2方法中的變量var一定是3火焰,所以變量b的值也一定是3。但是如果是“線程1”胧沫、“線程3”昌简、“線程2”這個順序占业,那么最后“線程2”method2方法中的b值是3,還是4呢纯赎?其結果是可能是3谦疾,也可能是4。的確“線程3”在執(zhí)行完method3方法后的確要unlock犬金,然后“線程2”有個lock念恍,但是這兩個線程用的不是同一個鎖,所以JMM這個兩個操作之間不符合八大happen-before中的任何一條晚顷,所以JMM不能保證“線程3”對var變量的修改對“線程2”一定可見峰伙,雖然“線程3”先于“線程2”發(fā)生。


對一個volatile變量的寫操作happen-before對此變量的任意操作:

volatile int a;
a = 1; //1
b = a;  //2

如果線程1 執(zhí)行//1该默,“線程2”執(zhí)行了//2,并且“線程1”執(zhí)行后,“線程2”再執(zhí)行,那么符合“volatile的happen-before原則”所以“線程2”中的a值一定是1词爬。


如果A操作 happen-before B操作,B操作happen-before C操作权均,那么A操作happen-before C操作:如果有如下代碼塊:

volatile int var;
int b;
int c;
b = 4; //1
var = 3; //2
c = var; //3
c = b; //4

假設“線程1”執(zhí)行//1 //2這段代碼,“線程2”執(zhí)行//3 //4這段代碼顿膨。如果某次的執(zhí)行順序如下:
//1 //2 //3 //4。那么有如下推導( hd(a,b)表示a happen-before b):

因為有hd(//1,//2) 叽赊、hd(//3,//4) (單線程的happen-before原則)
且hd(//2,//3) (volatile的happen-before原則)
所以有 hd(//1,//3),可導出hd(//1,//4) (happen-before原則的傳遞性)
所以變量c的值最后為4
如果某次的執(zhí)行順序如下:
//1 //3 //2// //4 那么最后4的結果就不能確定嘍恋沃。其原因是 //3 //2 直接符合上述八大原則中的任何一個,不能通過傳遞性推測出來什么必指。


通過對上面的四個原則的詳細解釋囊咏,省下的四個原則就比較顯而易見了。這里就不做詳細解釋了塔橡。歡迎積極留言大家一起討論梅割。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市葛家,隨后出現(xiàn)的幾起案子户辞,更是在濱河造成了極大的恐慌,老刑警劉巖癞谒,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件底燎,死亡現(xiàn)場離奇詭異,居然都是意外死亡弹砚,警方通過查閱死者的電腦和手機双仍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來桌吃,“玉大人朱沃,你說我怎么就攤上這事。” “怎么了逗物?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵搬卒,是天一觀的道長。 經常有香客問我敬察,道長秀睛,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任莲祸,我火速辦了婚禮蹂安,結果婚禮上,老公的妹妹穿的比我還像新娘锐帜。我一直安慰自己田盈,他們只是感情好,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布缴阎。 她就那樣靜靜地躺著允瞧,像睡著了一般。 火紅的嫁衣襯著肌膚如雪蛮拔。 梳的紋絲不亂的頭發(fā)上述暂,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天,我揣著相機與錄音建炫,去河邊找鬼畦韭。 笑死,一個胖子當著我的面吹牛肛跌,可吹牛的內容都是我干的艺配。 我是一名探鬼主播,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼衍慎,長吁一口氣:“原來是場噩夢啊……” “哼转唉!你這毒婦竟也來了?” 一聲冷哼從身側響起稳捆,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤赠法,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后眷柔,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體期虾,經...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年驯嘱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片喳坠。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡鞠评,死狀恐怖,靈堂內的尸體忽然破棺而出壕鹉,到底是詐尸還是另有隱情剃幌,我是刑警寧澤聋涨,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布,位于F島的核電站负乡,受9級特大地震影響牍白,放射性物質發(fā)生泄漏。R本人自食惡果不足惜抖棘,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一茂腥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧切省,春花似錦最岗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至芙盘,卻和暖如春驯用,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背儒老。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工蝴乔, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人贷盲。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓淘这,卻偏偏與公主長得像,于是被迫代替她去往敵國和親巩剖。 傳聞我的和親對象是個殘疾皇子铝穷,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法,類相關的語法佳魔,內部類的語法曙聂,繼承相關的語法,異常的語法鞠鲜,線程的語...
    子非魚_t_閱讀 31,581評論 18 399
  • layout: posttitle: 《Java并發(fā)編程的藝術》筆記categories: Javaexcerpt...
    xiaogmail閱讀 5,798評論 1 19
  • 從三月份找實習到現(xiàn)在宁脊,面了一些公司,掛了不少贤姆,但最終還是拿到小米榆苞、百度、阿里霞捡、京東坐漏、新浪、CVTE、樂視家的研發(fā)崗...
    時芥藍閱讀 42,184評論 11 349
  • 炎炎夏日暑難當赊琳,綠綠草坪酷見長街夭。 酣暢淋漓一場球,推心置腹一杯酒躏筏。
    堯_212a閱讀 161評論 0 0
  • 打開 Chrome 的開發(fā)者工具板丽,在 console 面板粘貼以下代碼然后執(zhí)行: window.sessionSt...
    忘言川閱讀 264評論 1 1