<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專(zhuān)注安卓開(kāi)發(fā)

      導(dǎo)航

      Java并發(fā)編程(十四)Java內(nèi)存模型

      1.共享內(nèi)存和消息傳遞

        線程之間的通信機(jī)制有兩種:共享內(nèi)存和消息傳遞;在共享內(nèi)存的并發(fā)模型里,線程之間共享程序的公共狀態(tài),線程之間通過(guò)寫(xiě)-讀內(nèi)存中的公共狀態(tài)來(lái)隱式進(jìn)行通信。在消息傳遞的并發(fā)模型里,線程之間沒(méi)有公共狀態(tài),線程之間必須通過(guò)明確的發(fā)送消息來(lái)顯式進(jìn)行通信。
      同步是指程序用于控制不同線程之間操作發(fā)生相對(duì)順序的機(jī)制。在共享內(nèi)存并發(fā)模型里,同步是顯式進(jìn)行的。工程師必須顯式指定某個(gè)方法或某段代碼需要在線程之間互斥執(zhí)行。在消息傳遞的并發(fā)模型里,由于消息的發(fā)送必須在消息的接收之前,因此同步是隱式進(jìn)行的。
      Java的并發(fā)采用的是共享內(nèi)存模型,Java線程之間的通信總是隱式進(jìn)行,整個(gè)通信過(guò)程對(duì)工程師完全透明。

       

      2.Java內(nèi)存模型的抽象
        在java中,所有實(shí)例域、靜態(tài)域和數(shù)組元素存儲(chǔ)在堆內(nèi)存中,堆內(nèi)存在線程之間共享(本文使用“共享變量”這個(gè)術(shù)語(yǔ)代指實(shí)例域,靜態(tài)域和數(shù)組元素)。局部變量,方法定義參數(shù)和異常處理器參數(shù)不會(huì)在線程之間共享,它們不會(huì)有內(nèi)存可見(jiàn)性問(wèn)題,也不受內(nèi)存模型的影響。
      Java線程之間的通信由Java內(nèi)存模型(本文簡(jiǎn)稱(chēng)為JMM)控制,JMM決定一個(gè)線程對(duì)共享變量的寫(xiě)入何時(shí)對(duì)另一個(gè)線程可見(jiàn)。從抽象的角度來(lái)看,JMM定義了線程和主內(nèi)存之間的抽象關(guān)系:線程之間的共享變量存儲(chǔ)在主內(nèi)存中,每個(gè)線程都有一個(gè)私有的本地內(nèi)存,本地內(nèi)存中存儲(chǔ)了該線程以讀/寫(xiě)共享變量的副本。本地內(nèi)存是JMM的一個(gè)抽象概念,并不真實(shí)存在。它涵蓋了緩存,寫(xiě)緩沖區(qū),寄存器以及其他的硬件和編譯器優(yōu)化。Java內(nèi)存模型的抽象示意圖如下:

      從上圖來(lái)看,線程A與線程B之間如要通信的話(huà),必須要經(jīng)歷下面2個(gè)步驟:

      1. 線程A把本地內(nèi)存A中更新過(guò)的共享變量刷新到主內(nèi)存中去。
      2. 線程B到主內(nèi)存中去讀取線程A之前已更新過(guò)的共享變量。

       

      3.從源代碼到指令序列的重排序

      在執(zhí)行程序時(shí)為了提高性能,編譯器和處理器常常會(huì)對(duì)指令做重排序。重排序分三種類(lèi)型:

      1. 編譯器優(yōu)化的重排序。編譯器在不改變單線程程序語(yǔ)義的前提下,可以重新安排語(yǔ)句的執(zhí)行順序。
      2. 指令級(jí)并行的重排序。現(xiàn)代處理器采用了指令級(jí)并行技術(shù)來(lái)將多條指令重疊執(zhí)行。如果不存在數(shù)據(jù)依賴(lài)性,處理器可以改變語(yǔ)句對(duì)應(yīng)機(jī)器指令的執(zhí)行順序。
      3. 內(nèi)存系統(tǒng)的重排序。由于處理器使用緩存和讀/寫(xiě)緩沖區(qū),這使得加載和存儲(chǔ)操作看上去可能是在亂序執(zhí)行。 

      從java源代碼到最終實(shí)際執(zhí)行的指令序列,會(huì)分別經(jīng)歷下面三種重排序:

      上述的1屬于編譯器重排序,2和3屬于處理器重排序。這些重排序都可能會(huì)導(dǎo)致多線程程序出現(xiàn)內(nèi)存可見(jiàn)性問(wèn)題。對(duì)于編譯器,JMM的編譯器重排序規(guī)則會(huì)禁止特定類(lèi)型的編譯器重排序(不是所有的編譯器重排序都要禁止)。對(duì)于處理器重排序,JMM的處理器重排序規(guī)則會(huì)要求java編譯器在生成指令序列時(shí),插入特定類(lèi)型的內(nèi)存屏障指令,通過(guò)內(nèi)存屏障指令來(lái)禁止特定類(lèi)型的處理器重排序(不是所有的處理器重排序都要禁止)。 
      JMM屬于語(yǔ)言級(jí)的內(nèi)存模型,它確保在不同的編譯器和不同的處理器平臺(tái)之上,通過(guò)禁止特定類(lèi)型的編譯器重排序和處理器重排序,為程序員提供一致的內(nèi)存可見(jiàn)性保證。

       

      4.happens-before簡(jiǎn)介
      happens-before是JMM最核心的概念,對(duì)于Java工程師來(lái)說(shuō),理解happens-before是理解JMM的關(guān)鍵。

      JMM的設(shè)計(jì)意圖

      在設(shè)計(jì)JMM需要考慮兩個(gè)關(guān)鍵因素:

      1. 工程師對(duì)內(nèi)存模型的使用,希望內(nèi)存模型易于理解和編程,工程師希望基于一個(gè)強(qiáng)內(nèi)存模型來(lái)編寫(xiě)代碼。
      2. 編譯器和處理器對(duì)內(nèi)存的實(shí)現(xiàn),希望內(nèi)存模型對(duì)他們的束縛越少越好,編譯器和處理器希望實(shí)現(xiàn)一個(gè)弱內(nèi)存模型。

      這兩個(gè)因素是互相矛盾的,所以JSR-133專(zhuān)家組設(shè)計(jì)時(shí)需要考慮到一個(gè)好的平衡點(diǎn):一方面為工程師提供足夠強(qiáng)的內(nèi)存可見(jiàn)性,另一方面要對(duì)編譯器和處理器的限制要盡量松些。

      我們來(lái)舉了例子:

      int a=10;   //A
      int b=20;   //B
      int c=a*b;  //C
      
      上面是一個(gè)簡(jiǎn)單的乘法運(yùn)算,并存在3個(gè)happens-before關(guān)系:
      1.  A happens-before B
      2.  B happens-before C
      3.  A happens-before C
      
      這三個(gè)happens-before關(guān)系中,2和3是必須的,但1是不必要的。因此,JMM把happens-before要求禁止的重排序分為兩類(lèi):
      1.會(huì)改變程序執(zhí)行結(jié)果的重排序。
      2.不會(huì)改變程序執(zhí)行結(jié)果的重排序。
      
      
      JMM對(duì)這兩種不同性質(zhì)的重排序,采取了不同的策略:
      1.對(duì)于會(huì)改變程序執(zhí)行結(jié)果的重排序,JMM要求編譯器和處理器必須禁止這種重排序。
      2.對(duì)于不會(huì)改變程序執(zhí)行結(jié)果的重排序,JMM要求編譯器和處理器不做要求,可以允許這種重排序。
      View Code

      happens-before的定義與規(guī)則

      JSR-133使用happens-before的概念來(lái)指定兩個(gè)操作之間的執(zhí)行順序,由于這兩個(gè)操作可以在一個(gè)線程內(nèi),也可以在不同的線程之間。因此,JMM可以通過(guò)happens-before關(guān)系向工程師提供跨線程的內(nèi)存可見(jiàn)性保證。

      happens-before規(guī)則如下: 
      1. 程序順序規(guī)則:一個(gè)線程中的每個(gè)操作,happens- before 于該線程中的任意后續(xù)操作。 
      2. 監(jiān)視器鎖規(guī)則:對(duì)一個(gè)監(jiān)視器鎖的解鎖,happens- before 于隨后對(duì)這個(gè)監(jiān)視器鎖的加鎖。 
      3. volatile變量規(guī)則:對(duì)一個(gè)volatile域的寫(xiě),happens- before 于任意后續(xù)對(duì)這個(gè)volatile域的讀。 
      4. 傳遞性:如果A happens- before B,且B happens- before C,那么A happens- before C。

       

      5.順序一致性

      順序一致性?xún)?nèi)存模型是一個(gè)理論參考模型,在設(shè)計(jì)的時(shí)候,處理器的內(nèi)存模型和編程語(yǔ)言的內(nèi)存模型都會(huì)以順序一致性?xún)?nèi)存模型為參考。

      數(shù)據(jù)競(jìng)爭(zhēng)與順序一致性

      當(dāng)程序未正確同步時(shí),就會(huì)存在數(shù)據(jù)競(jìng)爭(zhēng)。數(shù)據(jù)競(jìng)爭(zhēng)指的是:在一個(gè)線程中寫(xiě)一個(gè)變量,在另一個(gè)線程讀同一個(gè)變量,而且寫(xiě)和讀沒(méi)有通過(guò)同步來(lái)排序。 
      當(dāng)代碼中包含數(shù)據(jù)競(jìng)爭(zhēng)時(shí),程序的執(zhí)行往往產(chǎn)生違反直覺(jué)的結(jié)果。如果一個(gè)多線程程序能正確同步,這個(gè)程序?qū)⑹且粋€(gè)沒(méi)有數(shù)據(jù)競(jìng)爭(zhēng)的程序。 
      JMM對(duì)正確同步的多線程程序的內(nèi)存一致性做了如下保證: 
      如果程序是正確同步的,程序的執(zhí)行將具有順序一致性(sequentially consistent),即程序的執(zhí)行結(jié)果與該程序在順序一致性?xún)?nèi)存模型中的執(zhí)行結(jié)果相同。這里的同步是指廣義上的同步,包括對(duì)常用同步原語(yǔ)(synchronized,volatile和final)的正確使用。

      順序一致性模型

      順序一致性?xún)?nèi)存模型是一個(gè)被計(jì)算機(jī)科學(xué)家理想化了的理論參考模型,它為程序員提供了極強(qiáng)的內(nèi)存可見(jiàn)性保證。順序一致性?xún)?nèi)存模型有兩大特性:

      1. 一個(gè)線程中的所有操作必須按照程序的順序來(lái)執(zhí)行。
      2. (不管程序是否同步)所有線程都只能看到一個(gè)單一的操作執(zhí)行順序。在順序一致性?xún)?nèi)存模型中,每個(gè)操作都必須原子執(zhí)行且立刻對(duì)所有線程可見(jiàn)。

      順序一致性?xún)?nèi)存模型為程序員提供的視圖如下: 

      在概念上,順序一致性模型有一個(gè)單一的全局內(nèi)存,這個(gè)內(nèi)存通過(guò)一個(gè)左右擺動(dòng)的開(kāi)關(guān)可以連接到任意一個(gè)線程。同時(shí),每一個(gè)線程必須按程序的順序來(lái)執(zhí)行內(nèi)存讀/寫(xiě)操作。從上圖我們可以看出,在任意時(shí)間點(diǎn)最多只能有一個(gè)線程可以連接到內(nèi)存。當(dāng)多個(gè)線程并發(fā)執(zhí)行時(shí),圖中的開(kāi)關(guān)裝置能把所有線程的所有內(nèi)存讀/寫(xiě)操作串行化。

      順序一致性?xún)?nèi)存模型中的每個(gè)操作必須立即對(duì)任意線程可見(jiàn),但是在JMM中就沒(méi)有這個(gè)保證。未同步程序在JMM中不但整體的執(zhí)行順序是無(wú)序的,而且所有線程看到的操作執(zhí)行順序也可能不一致。比如,在當(dāng)前線程把寫(xiě)過(guò)的數(shù)據(jù)緩存在本地內(nèi)存中,且還沒(méi)有刷新到主內(nèi)存之前,這個(gè)寫(xiě)操作僅對(duì)當(dāng)前線程可見(jiàn);從其他線程的角度來(lái)觀察,會(huì)認(rèn)為這個(gè)寫(xiě)操作根本還沒(méi)有被當(dāng)前線程執(zhí)行。只有當(dāng)前線程把本地內(nèi)存中寫(xiě)過(guò)的數(shù)據(jù)刷新到主內(nèi)存之后,這個(gè)寫(xiě)操作才能對(duì)其他線程可見(jiàn)。在這種情況下,當(dāng)前線程和其它線程看到的操作執(zhí)行順序?qū)⒉灰恢隆?/span>

      同步程序的順序一致性

      我們接下來(lái)看看正確同步的程序如何具有順序一致性。

      class SynchronizedExample {
      int a = 0;
      boolean flag = false;
      
      public synchronized void writer() {
          a = 1;
          flag = true;
      }
      
      public synchronized void reader() {
          if (flag) {
              int i = a;
              ……
          }
      }
      }
      View Code

      上面示例代碼中,假設(shè)A線程執(zhí)行writer()方法后,B線程執(zhí)行reader()方法。這是一個(gè)正確同步的多線程程序。根據(jù)JMM規(guī)范,該程序的執(zhí)行結(jié)果將與該程序在順序一致性模型中的執(zhí)行結(jié)果相同。下面是該程序在兩個(gè)內(nèi)存模型中的執(zhí)行時(shí)序?qū)Ρ葓D:

      在順序一致性模型中,所有操作完全按程序的順序串行執(zhí)行。而在JMM中,臨界區(qū)內(nèi)的代碼可以重排序(但JMM不允許臨界區(qū)內(nèi)的代碼“逸出”到臨界區(qū)之外,那樣會(huì)破壞監(jiān)視器的語(yǔ)義)。JMM會(huì)在退出監(jiān)視器和進(jìn)入監(jiān)視器這兩個(gè)關(guān)鍵時(shí)間點(diǎn)做一些特別處理,使得線程在這兩個(gè)時(shí)間點(diǎn)具有與順序一致性模型相同的內(nèi)存視圖。雖然線程A在臨界區(qū)內(nèi)做了重排序,但由于監(jiān)視器的互斥執(zhí)行的特性,這里的線程B根本無(wú)法“觀察”到線程A在臨界區(qū)內(nèi)的重排序。這種重排序既提高了執(zhí)行效率,又沒(méi)有改變程序的執(zhí)行結(jié)果。 
      從這里我們可以看到JMM在具體實(shí)現(xiàn)上的基本方針:在不改變(正確同步的)程序執(zhí)行結(jié)果的前提下,盡可能的為編譯器和處理器的優(yōu)化打開(kāi)方便之門(mén)。

      未同步程序的順序一致性

      JMM不保證未同步程序的執(zhí)行結(jié)果與該程序在順序一致性模型中的執(zhí)行結(jié)果一致。因?yàn)槲赐匠绦蛟陧樞蛞恢滦阅P椭袌?zhí)行時(shí),整體上是無(wú)序的,其執(zhí)行結(jié)果無(wú)法預(yù)知。保證未同步程序在兩個(gè)模型中的執(zhí)行結(jié)果一致毫無(wú)意義。 
      和順序一致性模型一樣,未同步程序在JMM中的執(zhí)行時(shí),整體上也是無(wú)序的,其執(zhí)行結(jié)果也無(wú)法預(yù)知。 
      同時(shí),未同步程序在這兩個(gè)模型中的執(zhí)行特性有下面幾個(gè)差異:

      1. 順序一致性模型保證單線程內(nèi)的操作會(huì)按程序的順序執(zhí)行,而JMM不保證單線程內(nèi)的操作會(huì)按程序的順序執(zhí)行(比如上面正確同步的多線程程序在臨界區(qū)內(nèi)的重排序)。
      2. 順序一致性模型保證所有線程只能看到一致的操作執(zhí)行順序,而JMM不保證所有線程能看到一致的操作執(zhí)行順序。
      3. JMM不保證對(duì)64位的long型和double型變量的讀/寫(xiě)操作具有原子性,而順序一致性模型保證對(duì)所有的內(nèi)存讀/寫(xiě)操作都具有原子性。

      對(duì)于第三個(gè)差異:在一些32位的處理器上,如果要求對(duì)64位數(shù)據(jù)的讀/寫(xiě)操作具有原子性,會(huì)有比較大的開(kāi)銷(xiāo)。為了照顧這種處理器,java語(yǔ)言規(guī)范鼓勵(lì)但不強(qiáng)求JVM對(duì)64位的long型變量和double型變量的讀/寫(xiě)具有原子性。當(dāng)JVM在這種處理器上運(yùn)行時(shí),會(huì)把一個(gè)64位long/ double型變量的讀/寫(xiě)操作拆分為兩個(gè)32位的讀/寫(xiě)操作來(lái)執(zhí)行。這兩個(gè)32位的讀/寫(xiě)操作可能會(huì)被分配到不同的總線事務(wù)中執(zhí)行,此時(shí)對(duì)這個(gè)64位變量的讀/寫(xiě)將不具有原子性。 
      當(dāng)單個(gè)內(nèi)存操作不具有原子性,將可能會(huì)產(chǎn)生意想不到后果。請(qǐng)看下面示意圖: 
      這里寫(xiě)圖片描述

      如上圖所示,假設(shè)處理器A寫(xiě)一個(gè)long型變量,同時(shí)處理器B要讀這個(gè)long型變量。處理器A中64位的寫(xiě)操作被拆分為兩個(gè)32位的寫(xiě)操作,且這兩個(gè)32位的寫(xiě)操作被分配到不同的寫(xiě)事務(wù)中執(zhí)行。同時(shí)處理器B中64位的讀操作被拆分為兩個(gè)32位的讀操作,且這兩個(gè)32位的讀操作被分配到同一個(gè)的讀事務(wù)中執(zhí)行。當(dāng)處理器A和B按上圖的時(shí)序來(lái)執(zhí)行時(shí),處理器B將看到僅僅被處理器A“寫(xiě)了一半“的無(wú)效值。

       

      posted on 2016-12-23 01:06  安卓筆記俠  閱讀(380)  評(píng)論(0)    收藏  舉報(bào)

      主站蜘蛛池模板: 99久久免费精品色老| 成人精品视频一区二区三区| 精品国产美女福到在线不卡| 武鸣县| 亚洲精品综合久久国产二区| 奶头好大揉着好爽视频| 乱人伦人妻中文字幕无码久久网| 97久久精品午夜一区二区| 黄色亚洲一区二区在线观看| 国产日产免费高清欧美一区| japan黑人极大黑炮| 两个人看的www免费视频中文| 色多多性虎精品无码av| 色多多性虎精品无码av| 国产精品美女一区二三区| 欧美一级黄色影院| 国产日韩av二区三区| 亚洲综合在线亚洲优优色| 男女性高爱潮免费网站| 成熟女人特级毛片www免费| 亚洲制服无码一区二区三区| 婷婷六月色| 国产午夜影视大全免费观看| 亚洲欧美人成网站在线观看看| 欧美性猛交xxxx乱大交极品| 国产成人高清亚洲综合| 色综合久久天天综线观看| 亚洲人成小说网站色在线| 成人亚洲综合av天堂| 亚洲精品国产美女久久久| 5555国产在线观看| 黄色免费在线网址| 久久精品免费自拍视频| 护士的小嫩嫩好紧好爽| 久久婷婷国产精品香蕉| 丰满人妻被黑人猛烈进入| 久久综合偷拍视频五月天| 亚洲2017天堂色无码| 亚洲国产区男人本色vr| 亚洲中文字幕一区二区| аⅴ天堂国产最新版在线中文|