最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java并發(fā)編程之volatile與JMM多線程內(nèi)存模型

 更新時(shí)間:2022年05月12日 14:55:35   作者:字母哥哥  
這篇文章主要介紹了Java并發(fā)volatile與JMM多線程內(nèi)存模型,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

圖片

一、通過程序看現(xiàn)象

在開始為大家講解Java 多線程緩存模型之前,我們先看下面的這一段代碼。這段代碼的邏輯很簡(jiǎn)單:主線程啟動(dòng)了兩個(gè)子線程,一個(gè)線程1、一個(gè)線程2。線程1先執(zhí)行,sleep睡眠2秒鐘之后線程2執(zhí)行。兩個(gè)線程使用到了一個(gè)共享變量shareFlag,初始值為false。如果shareFlag一直等于false,線程1將一直處于死循環(huán)狀態(tài),所以我們?cè)诰€程2中將shareFlag設(shè)置為true。

public class VolatileTest {
  public static boolean shareFlag = false;
  public static void main(String[] args) throws InterruptedException {
    new Thread(() -> {
      System.out.print("開始執(zhí)行線程1 =>");
      while (!shareFlag){  //shareFlag = false則一直死循環(huán)
        //System.out.println("shareFlag=" + shareFlag);
      }
      System.out.print("線程1執(zhí)行完成 =>");
    }).start();
    Thread.sleep(2000);
    new Thread(() -> {
      System.out.print("開始執(zhí)行線程2 =>");
      shareFlag = true;
      System.out.print("線程2執(zhí)行完成 =>");
    }).start();
  }
}

如果你沒有學(xué)過JMM線程模型,可能你看完上面的代碼,希望得到的輸出結(jié)果是下面這樣的:

開始執(zhí)行線程1 =>開始執(zhí)行線程2 =>線程2執(zhí)行完成 =>線程1執(zhí)行完成=>

如下圖所示,正常人理解這段代碼,首先執(zhí)行線程1進(jìn)入循環(huán),線程2修改shareFlag=true,線程1跳出循環(huán)。所以跳出循環(huán)的線程1會(huì)打印"線程1執(zhí)行完成=>",但是經(jīng)過筆者實(shí)驗(yàn),**"線程1執(zhí)行完成=>"不會(huì)被打印,線程1也沒有跳出死循環(huán)**,這是為什么呢?

圖片

二、為什么會(huì)產(chǎn)生這種現(xiàn)象(JMM模型)?

要解釋上面提到的問題,我們就需要學(xué)習(xí)JMM(Java Memory Model)Java 內(nèi)存模型,筆者覺得叫做Java多線程內(nèi)存模型更準(zhǔn)確一些。

圖片

  • 首先,在JMM中每個(gè)線程有自己的工作內(nèi)存,在程序啟動(dòng)的時(shí)候,線程將共享變量加載(read&load)到自己的工作內(nèi)存中,加載到線程工作內(nèi)存中的內(nèi)存變量是主內(nèi)存中共享變量的副本。也就是說此時(shí)shareFlag在內(nèi)存中有三個(gè)副本,值都等于false。
  • 當(dāng)線程2執(zhí)行shareFlag=true的時(shí)候?qū)⑵涔ぷ鲀?nèi)存副本修改為shareFlag=true,同時(shí)將副本的值同步寫回(store&write)到主內(nèi)存中。
  • 但是線程1的工作內(nèi)存中的shareFlag=false沒有發(fā)生變化,所以線程1一直處于死循環(huán)之中。

三、MESI 緩存一致性協(xié)議

按照上文的實(shí)驗(yàn)以及JMM模型,線程2修改的共享變量的值,線程1感知不到。那怎么樣才能讓線程1感知到共享變量的值發(fā)生了變化呢?其實(shí)也很簡(jiǎn)單,給shareFlag共享變量加上volatile關(guān)鍵字就可以了。

public volatile static boolean shareFlag = false;

其底層原理是這樣的,加上volatile關(guān)鍵字提示JMM遵循MESI 緩存一致性協(xié)議,該協(xié)議包含如下的緩存使用規(guī)范(看不懂可以不看,下文會(huì)用簡(jiǎn)單的語言及例子描述一下)。

  1. Modified:代表當(dāng)前Cache行的數(shù)據(jù)是修改過的(Dirty),并且只在當(dāng)前CPU的Cache中是修改過的;此時(shí)該Cache行的數(shù)據(jù)與其他Cache中的數(shù)據(jù)不同,與內(nèi)存中該行的數(shù)據(jù)也不同。
  2. Exclusive:代表當(dāng)前Cache行的數(shù)據(jù)是有效數(shù)據(jù),其他CPU的Cache中沒有這行數(shù)據(jù);并且當(dāng)前Cache行數(shù)據(jù)與內(nèi)存中的數(shù)據(jù)相同。
  3. Shared:代表多個(gè)CPU的Cache中都會(huì)緩存有這行數(shù)據(jù),并且Cache中的數(shù)據(jù)與內(nèi)存中的數(shù)據(jù)一致;
  4. Invalid:表示當(dāng)前Cache行中的數(shù)據(jù)無效;

圖片

上文中的緩存使用規(guī)范可能過于復(fù)雜,簡(jiǎn)單的說就是

  • 當(dāng)線程2修改shareFlag的時(shí)候(參考Modify),告知bus總線我修改了共享變量shareFlag,
  • 線程1對(duì)Bus總線進(jìn)行監(jiān)聽,當(dāng)它獲知共享變量shareFlag發(fā)生了修改就會(huì)將自己工作內(nèi)存中的shareFlag副本刪除使其失效。
  • 當(dāng)線程1再次需要使用到shareFlag的時(shí)候,發(fā)現(xiàn)工作內(nèi)存中沒有shareFlag變量副本,就會(huì)重新從主內(nèi)存中加載(read&load)

到此這篇關(guān)于Java并發(fā)-volatile與JMM多線程內(nèi)存模型的文章就介紹到這了,更多相關(guān)java多線程內(nèi)存模型內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Jmeter參數(shù)化實(shí)現(xiàn)原理及過程解析

    Jmeter參數(shù)化實(shí)現(xiàn)原理及過程解析

    這篇文章主要介紹了Jmeter參數(shù)化實(shí)現(xiàn)原理及過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07
  • MyBatis批量更新(update foreach)報(bào)錯(cuò)問題

    MyBatis批量更新(update foreach)報(bào)錯(cuò)問題

    這篇文章主要介紹了MyBatis批量更新(update foreach)報(bào)錯(cuò)問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • java jvm的知識(shí)詳細(xì)介紹

    java jvm的知識(shí)詳細(xì)介紹

    這篇文章主要介紹了java jvm的知識(shí)詳細(xì)介紹的相關(guān)資料,這里對(duì)java jvm中的堆內(nèi)存和棧內(nèi)存等基礎(chǔ)知識(shí)做了詳細(xì)介紹,需要的朋友可以參考下
    2016-11-11
  • Java 8 中的 10 個(gè)特性總結(jié)及詳解

    Java 8 中的 10 個(gè)特性總結(jié)及詳解

    本主要介紹Java 8中的新特性,這里整理了相關(guān)資料并整理了10個(gè)特性,逐一介紹說明,有興趣的朋友可以參考下
    2016-09-09
  • 最新評(píng)論

    上林县| 武义县| 龙岩市| 探索| 嘉禾县| 道真| 榆社县| 烟台市| 兴山县| 蒙山县| 萨嘎县| 靖江市| 运城市| 玛纳斯县| 烟台市| 永康市| 赤峰市| 和龙市| 苗栗县| 专栏| 申扎县| 三都| 景东| 巴里| 游戏| 澄城县| 泾阳县| 广元市| 南丰县| 阿克| 闽清县| 新绛县| 屏山县| 汤原县| 琼中| 武宣县| 卢湾区| 琼结县| 湖州市| 仲巴县| 瑞安市|