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被中斷線程的檢測到中斷發送的代碼。
  • 線程終結的happen-before原則:線程中的所有操作都happen-before線程的終止檢測。
  • 對象創建的happen-before原則:一個對象的初始化完成先于他的finalize方法調用。

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


在同一個線程中,書寫在前面的操作happen-before后面的操作: 好多文章把這理解成書寫在前面先發生于書寫在后面的代碼,但是指令重排序,確實可以讓書寫在后面的代碼先于書寫在前面的代碼發生。這是里把happen-before 理解成“先于什么發生”,其實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虛擬機不許可操作系統對//1 //2 操作進行指令重排序,即不可能有//2 在//1之前發生。但是對于下面的代碼:

?

int a = 3;
int b = 4;

兩個語句直接沒有依賴關系,所以指令重排序可能發生,即對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執行的代碼:
A.getInstance().method1(); 

?

//線程2執行的代碼:
A.getInstance().method2(); 

?

//線程3執行的代碼:
A.getInstance().method3();

如果某個時刻執行完“線程1” 馬上執行“線程2”,因為“線程1”執行A類的method1方法后肯定要釋放鎖,“線程2”在執行A類的method2方法前要先拿到鎖,符合“鎖的happen-before原則”,那么在“線程2”method2方法中的變量var一定是3,所以變量b的值也一定是3。但是如果是“線程1”、“線程3”、“線程2”這個順序,那么最后“線程2”method2方法中的b值是3,還是4呢?其結果是可能是3,也可能是4。的確“線程3”在執行完method3方法后的確要unlock,然后“線程2”有個lock,但是這兩個線程用的不是同一個鎖,所以JMM這個兩個操作之間不符合八大happen-before中的任何一條,所以JMM不能保證“線程3”對var變量的修改對“線程2”一定可見,雖然“線程3”先于“線程2”發生。


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

?

volatile int a;

?

a = 1; //1

?

b = a;  //2

如果線程1 執行//1,“線程2”執行了//2,并且“線程1”執行后,“線程2”再執行,那么符合“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”執行//1 //2這段代碼,“線程2”執行//3 //4這段代碼。如果某次的執行順序如下:
//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
如果某次的執行順序如下:
//1 //3 //2// //4 那么最后4的結果就不能確定嘍。其原因是 //3 //2 直接符合上述八大原則中的任何一個,不能通過傳遞性推測出來什么。


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



作者:aworker
鏈接:https://www.jianshu.com/p/1508eedba54d
來源:簡書
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/386513.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/386513.shtml
英文地址,請注明出處:http://en.pswp.cn/news/386513.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

centos7.0利用yum快速安裝mysql8.0

我這里直接使用MySQL Yum存儲庫的方式快速安裝: 抽象 MySQL Yum存儲庫提供用于在Linux平臺上安裝MySQL服務器,客戶端和其他組件的RPM包。這些軟件包還可以升級和替換從Linux發行版本機軟件存儲庫安裝的任何第三方MySQL軟件包,如果可以從MySQL…

騰訊3輪面試都問了Android事件分發,論程序員成長的正確姿勢

前言 這些題目是網友去美團等一線互聯網公司面試被問到的題目。筆者從自身面試經歷、各大網絡社交技術平臺搜集整理而成,熟悉本文中列出的知識點會大大增加通過前兩輪技術面試的幾率。 主要分為以下幾部分: (1)Android面試題 …

happens-before規則和as-if-serial語義

概述 本文大部分整理自《Java并發編程的藝術》,溫故而知新,加深對基礎的理解程度。 指令序列的重排序 我們在編寫代碼的時候,通常自上而下編寫,那么希望執行的順序,理論上也是逐步串行執行,但是為了提高…

安裝nodejs

1.安裝nodejs:node-v8.12.0-x64.msi; 2.檢測是否安裝成功: 3.地址欄打開命令行:輸入 cmd回車 4.檢測node是否安裝成功:node -v 看到版本號就是安裝成功了 5.檢測npm是否成功:npm -v 是安裝成功了 6、如果npm成功了,把 package.js…

貼片晶振無源石英諧振器直插晶振

貼片晶振 貼片晶振3.579M~25MHz無源石英諧振器直插晶振 文章目錄 貼片晶振前言一、貼片晶振3.579M~25MHz無源石英諧振器直插晶振二、屬性三、技術參數總結前言 貼片晶振(Surface Mount Crystal Oscillator)是一種采用表面貼裝技術進行安裝的晶振。它的主要特點是封裝小巧、安…

這些新技術你們都知道嗎?成功收獲美團,小米安卓offer

前言 近期被兩則消息刷屏,【字節跳動持續大規模招聘,全年校招超過1萬人】【騰訊有史以來最大規模的校招啟動】當然Android崗位也包含在內,因此Android還是有很多機會的。結合往期面試的同學(主要是校招)經驗&#xff…

CompareAndSwap原子操作原理

在翻閱AQS(AbstractQueuedSynchronizer)類的過程中,發現其進行原子操作的時候采用的是CAS。涉及的代碼如下: 1: private static final Unsafe unsafe Unsafe.getUnsafe(); 2: private static final long stateOffset; 3: private static f…

STemWin移植筆記

實現將STemWin圖形庫移植到STM32F103ZET中,記錄簡單的操作步驟,以便自己后續查閱。 1/ 從官網獲取STemWin庫的壓縮包en.stemwin.zip。 2/ 解壓后,在路徑STemWin_Library_V1.2.0\Libraries\STemWinLibrary532下可以找到庫文件。 3/ 移植前的準…

這些新技術你們都知道嗎?看這一篇就夠了!

前言 現在已經進入招聘季節,本篇文章旨在分享知名互聯網企業面試官面試方法和心得,希望通過本文的閱讀能給程序員帶來不一樣的面試體驗和感受,放松面試心態,積極備戰! 面試題 PS:由于文章篇幅問題&#x…

spring boot redis 分布式鎖

yml文件 redis:host: 127.0.0.1port: 40197password: 123456timeout: 5000database: 0jedis:pool:min-idle: 0max-idle: 8max-active: 8max-wait: -1 RedisConfig.java import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.support.spring.FastJsonRedisSerializer…

mysql函數(二.數字函數)

數字函數 1.ROUND(X) 四舍五入取整數 ROUND(X,D) 四舍五入根據D幾,來保留幾位小數 (1)四舍五入取整數 select ROUND(1.567); 結果:2 (2)四舍五入根據D2,來保留2位小數 select ROUND(1.567,2)DESC; 結果:1.57 2.CEIL…

這份1307頁Android面試全套真題解析,源碼+原理+手寫框架

前言 前不久,幾個朋友聚會,談到了現在的后輩,我就說起了那個大三就已經拿到網易offer的小學弟。 這個學弟是00后,專升本進入我們學校的。進來后就非常努力,每次上課都是第一個到教室的,每次都是坐第一排&…

CAS的ABA問題描述 AtomicStampReference

CAS的ABA問題描述 在CAS操作的時候,其他線程將當前變量的值從A改成B,又改回A;CAS線程用期望值A與當前變量比較的時候,發現當前變量沒有變,于是CAS就將當前變量進行了交換操作,但其實當前變量改變過&#x…

[轉]OpenContrail 體系架構文檔

OpenContrail 體系架構文檔英文原文:http://opencontrail.org/opencontrail-architecture-documentation/ 翻譯者:KkBLuE知行合一 其微信號:kkbluepublic, SDNAP.com翻譯整理 OpenContrail 體系架構文檔 1 概述 1.1 使用案例 1…

這份354頁筆記的Android進階知識+大廠高頻面試題,絕對干貨

程序員與別的專業有所不同,其他專業都是越老越香,而程序員卻是一個例外,因為計算機技術更新太快,而且工作強度很大,因此大部分程序員只會寫 3 年代碼。3 年后要不晉升做項目經理,要么轉行,個別研…

原子性 atomic 類用法

當程序更新一個變量時,如果多線程同時更新這個變量,可能得到期望之外的值,比如變量i1,A線程更新i1,B線程也更新i1,經過兩個線程操作之后可能i不等于3,而是等于2。因為A和B線程在更新變量i的時候…

這是一份用心整理的Android面試總結,聰明人已經收藏了!

前言 本文想分享的是如何準備阿里面試的以及面試過程的所想所得,希望能幫到你。 首先,可能要讓你們失望的是,這篇文章不會有大篇幅的面試題答案。如果想要看這方面的內容,可以看我之前的文章。感謝關注 很多人準備面試的時候&a…

git 技能圖

---- 轉載于:https://www.cnblogs.com/WHWWHW/p/11136606.html

AtomicStampedReference源碼分析

之前的文章已經介紹過CAS的操作原理,它雖然能夠保證數據的原子性,但還是會有一個ABA的問題。 那么什么是ABA的問題呢?假設有一個共享變量“num”,有個線程A在第一次進行修改的時候把num的值修改成了33。修改成功之后,緊接著又立刻…

django:bootstrap table加載django返回的數據

bootstrap table加載表格數據有兩類方式: 一種通過data屬性的方式配置,一種是javascipt方式配置 這里看js配置方式: 1、當數據源為.json文件時 url參數寫上json文件的地址就行,但是json文件格式必須為json格式(2種): a:一種為json…