JMM中happens-before的原理和使用方法

這篇文章主要介紹“JMM中happens-before的原理和使用方法”,在日常操作中,相信很多人在JMM中happens-before的原理和使用方法問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”JMM中happens-before的原理和使用方法”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

專注于為中小企業提供成都網站設計、成都做網站服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業臺江免費做網站提供優質的服務。我們立足成都,凝聚了一批互聯網行業人才,有力地推動了千余家企業的穩健成長,幫助中小企業通過網站建設實現規模擴充和轉變。

在JMM中有一個很重要的概念對于我們了解JMM有很大的幫助,那就是happens-before規則。happens-before規則非常重要,它是判斷數據是否存在競爭、線程是否安全的主要依據。JSR-133S使用happens-before概念闡述了兩個操作之間的內存可見性。在JMM中,如果一個操作的結果需要對另一個操作可見,那么這兩個操作則存在happens-before關系。

那什么是happens-before呢?在JSR-133中,happens-before關系定義如下:

  1. 如果一個操作happens-before另一個操作,那么意味著第一個操作的結果對第二個操作可見,而且第一個操作的執行順序將排在第二個操作的前面。

  2. 兩個操作之間存在happens-before關系,并不意味著Java平臺的具體實現必須按照happens-before關系指定的順序來執行。如果重排序之后的結果,與按照happens-before關系來執行的結果一致,那么這種重排序并不非法(也就是說,JMM允許這種重排序)

happens-before規則如下:

  1. 程序順序規則:一個線程中的每一個操作,happens-before于該線程中的任意后續操作。

  2. 監視器規則:對一個鎖的解鎖,happens-before于隨后對這個鎖的加鎖。

  3. volatile規則:對一個volatile變量的寫,happens-before于任意后續對一個volatile變量的讀。

  4. 傳遞性:若果A happens-before B,B happens-before C,那么A happens-before C。

  5. 線程啟動規則:Thread對象的start()方法,happens-before于這個線程的任意后續操作。

  6. 線程終止規則:線程中的任意操作,happens-before于該線程的終止監測。我們可以通過Thread.join()方法結束、Thread.isAlive()的返回值等手段檢測到線程已經終止執行。

  7. 線程中斷操作:對線程interrupt()方法的調用,happens-before于被中斷線程的代碼檢測到中斷事件的發生,可以通過Thread.interrupted()方法檢測到線程是否有中斷發生。

  8. 對象終結規則:一個對象的初始化完成,happens-before于這個對象的finalize()方法的開始。

以上8條happens-before規則都比較簡單,這里LZ只分析第3條volatile變量規則,分析如下:

JMM中happens-before的原理和使用方法

從上圖中,我們看到存在4條happens-before關系,它們分別如下:

  • 1 happens-before 2 和 3 happens-before 4 是有由程序順序性規則產生的。

  • 2 happens-before 3 是由volatile規則產生的。上面提到過,一個volatile變量的讀,總能看到之前對這個volatile變量的寫入。

  • 1 happens-before 4 是由傳遞性規則產生的。

讀到這里,可能很多童鞋會把happens-before理解為“時間上的先后順序”,在這里LZ特別強調happens-hefore不能理解為“時間上的先后順序”,下面LZ用一段代碼解釋寫happens-before和“時間上的先后順序”的不同,代碼如下:

public class VolatileTest4 {
    private int a = 0;
    public int getA() {
        return a;
    }
    public void setA(int a) {
        this.a = a;
    }
}

上面代碼就是一組簡單的setter/getter方法,現在假設現在有兩個線程A和B,線程A先(這里指時間上的先執行)執行setA(10),然后線程B訪問同一個對象的getA()方法,那么此時線程B收到的返回值是對少呢?

答案是:不確定

我們來一次分析下happens-before的各項原則:

  1. 這里兩個方法分別是在兩個線程中被調用,不在一個線程中,這里程序順序性就不適用了

  2. 代碼中沒有同步快,所有監視器規則也不適用

  3. 代碼中變量a是一個普通變量,所以volatile規則也不適用

  4. 后面的線程啟動、中斷、終止和對象的終結和這里完全沒有關系,因此這些規則也是不適用的

  5. 沒有一條happens-before適用,因此傳遞性規則也不適用

在這里,雖然線程A在時間上先于線程B執行,但是由于代碼完全不適用happens-before規則,因此我們無法確定先B收到的值時多少。也就是說上面代碼是線程不安全的。

對于上面代碼,那我們如何修復線程不安全這個問題呢?這里,我們只要滿足happens-before規則中2、3的任意一種規則就可以了。即要么把setter/getter方法定義為synchronized方法,要么在變量a上加volatile修飾符。

通過上面的例子,我們可以得出結論:一個操作“時間上的先發生”不代表這個操作會happens-before其它操作。那一個操作happens-before其它操作,是否就表示這個操作是“時間上先發生”的呢?答案也是否定的,我們來看看下面一個示例:

int i = 1;
int m = 2;

上面兩個賦值操作在同一個線程中,根據程序順序性規則,“int i = 1;"這個操作happens-before ”int m = 2;“這個操作,但是”int m = 2;“這個操作完全有可能被處理器先執行,這并不影響happens-before原則的正確性。因為這種重排序在JMM中是允許的。

最后我們得出的結論是:時間先后順序與happens-before原則之間基本沒有太大的關系,所以我們在衡量并發安全問題的時候不要受到時間順序的干擾,一切必須以happens-before原則為準。 

到此,關于“JMM中happens-before的原理和使用方法”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注創新互聯網站,小編會繼續努力為大家帶來更多實用的文章!

當前文章:JMM中happens-before的原理和使用方法
轉載來于:http://m.kartarina.com/article4/pgoeoe.html

成都網站建設公司_創新互聯,為您提供建站公司關鍵詞優化企業網站制作全網營銷推廣微信小程序營銷型網站建設

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯

微信小程序開發
主站蜘蛛池模板: 97在线视频人妻无码| 国产成人无码一区二区在线观看| 国产又爽又黄无码无遮挡在线观看 | 无码国产精品一区二区免费3p| 精品欧洲av无码一区二区| 国产成人无码精品久久二区三区| 亚洲av无码一区二区三区乱子伦| 精品无码成人网站久久久久久| 无码一区二区三区视频| 亚洲?v无码国产在丝袜线观看 | 十八禁无码免费网站| 手机在线观看?v无码片| 无码国产精品一区二区免费式直播 | 中文无码AV一区二区三区 | 日韩精品成人无码专区免费| 亚洲日韩精品一区二区三区无码 | 大桥久未无码吹潮在线观看| 亚洲av无码成人影院一区 | 国产成人无码精品久久久小说| 国产av无码专区亚洲av果冻传媒| 亚洲国产精品无码久久| 色窝窝无码一区二区三区成人网站| 亚洲国产综合无码一区二区二三区 | 亚洲国产精品无码久久九九| 无码视频一区二区三区| 一本大道在线无码一区| 无码人妻丰满熟妇区BBBBXXXX| 国产精品亚洲а∨无码播放 | 亚洲啪啪AV无码片| 国产乱子伦精品无码专区| 无码少妇A片一区二区三区| 久久午夜福利无码1000合集| 亚洲av片不卡无码久久| 人妻无码一区二区不卡无码av| 国产日韩精品中文字无码| 中文字幕av无码专区第一页 | 久久99精品久久久久久hb无码| 人妻无码久久一区二区三区免费| 亚洲AV无码成人专区片在线观看 | 亚洲国产精品无码久久久不卡| 亚洲级αV无码毛片久久精品|