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

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

專注于為中小企業(yè)提供成都網(wǎng)站設(shè)計、成都做網(wǎng)站服務(wù),電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)臺江免費做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了千余家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實現(xiàn)規(guī)模擴充和轉(zhuǎn)變。

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

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

  1. 如果一個操作happens-before另一個操作,那么意味著第一個操作的結(jié)果對第二個操作可見,而且第一個操作的執(zhí)行順序?qū)⑴旁诘诙€操作的前面。

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

happens-before規(guī)則如下:

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

  2. 監(jiān)視器規(guī)則:對一個鎖的解鎖,happens-before于隨后對這個鎖的加鎖。

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

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

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

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

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

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

以上8條happens-before規(guī)則都比較簡單,這里L(fēng)Z只分析第3條volatile變量規(guī)則,分析如下:

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

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

  • 1 happens-before 2 和 3 happens-before 4 是有由程序順序性規(guī)則產(chǎn)生的。

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

  • 1 happens-before 4 是由傳遞性規(guī)則產(chǎn)生的。

讀到這里,可能很多童鞋會把happens-before理解為“時間上的先后順序”,在這里L(fēng)Z特別強調(diào)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方法,現(xiàn)在假設(shè)現(xiàn)在有兩個線程A和B,線程A先(這里指時間上的先執(zhí)行)執(zhí)行setA(10),然后線程B訪問同一個對象的getA()方法,那么此時線程B收到的返回值是對少呢?

答案是:不確定

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

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

  2. 代碼中沒有同步快,所有監(jiān)視器規(guī)則也不適用

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

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

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

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

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

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

int i = 1;
int m = 2;

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

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

到此,關(guān)于“JMM中happens-before的原理和使用方法”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬嵱玫奈恼拢?/p>

當(dāng)前文章:JMM中happens-before的原理和使用方法
轉(zhuǎn)載來于:http://muchs.cn/article4/pgoeoe.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供建站公司、關(guān)鍵詞優(yōu)化、企業(yè)網(wǎng)站制作全網(wǎng)營銷推廣、微信小程序營銷型網(wǎng)站建設(shè)

廣告

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

微信小程序開發(fā)