Java併發編程原理-內存模型

基本概念

程序

代碼,完成某一任務的代碼序列(靜態的概念)

進程

程序在某些數據上的一次運行,有開始、有結束、有生命週期(動態的概念)

線程

一個進程包含一個或多個線程,佔有該資源(內存、CPU等)的獨立單元(微觀的概念)

JVM與線程

JVM什麼時候啓動 :Java程序類被調用的時候,JVM線程會啓動,然後再啓動其他線程(如:main)

JVM內存區域

JVM內存區域是人爲劃分的區域,實際的物理區域並不會如此劃分的。
Java內存區域

  1. 方法區:類信息、常量、static、JIT(即時編譯) ,如常用的反射加載。(信息共享)
  2. 堆區域:實例對象 GC(垃圾回收)工作的主要對象。(信息共享、OOM內存溢出)
  3. VM stack(棧):Java方法運行的內存模型(OOM內存溢出)。如下:
    VM stack
  4. PC:Java線程的私有數據,這個數據就是執行下一條指令的地址。
  5. native method stack:線程私有的區域 ,與虛擬機 jvm的native方法有關,一般情況下我們編碼開發過程中是不關心。

JVM內存模型

Java Memory Model(JMM),是一種規範,是一種抽象的模型。
JMM

  1. 主內存:共享的信息
  2. 工作內存:私有信息,如果是基本數據類型,直接分配到工作內存;如果是引用的地址,存放在工作內存;如果是引用的對象,那麼存放在堆中
  3. 工作方式:
    A)線程修改私有數據,直接在工作空間修改
    B)線程修改共享數據,把數據複製到工作空間中去,在工作空間中修改,修改完成以後,刷新內存中的數據。有可能存在線程不安全(不一致性)

其中,JVM內存區域劃分就是根據JVM的內存模型(JMM)來進行實現的。JMM是模型,JVM內存區域是實現方案。工作內存對應的VM Stack,存儲私有信息,方法區和堆對應的主內存,可以進行信息共享。

硬件內存架構與Java內存模型

  1. 硬件架構
    硬件架構
    • CPU緩存的一致性問題:併發處理的不同步,如內存中的變量X=1,CPU1修改X=2,此時CPU2讀取X的值,那麼CPU2讀取的X的值有可能爲1(由於併發處理,此時Cache中的2還未同步到內存中),也有可能爲2.
    • 解決方案:
      • 總線(BUS)加鎖、 降低CPU的吞吐量,但也降低了CPU的處理能力
      • 緩存上的一致性協議(MESI)
        當CPU在Cache中操作數據時,如果該數據是共享變量,數據在CACHE讀到寄存器中,進行新修改,並更新內存數據
        CacheLINE(信號線)置無效,其他的CPU就不從Cache中讀取,而從內存中去讀數據。
  2. Java線程與硬件處理器
    在這裏插入圖片描述
  3. Java內存模型與硬件內存架構的關係
    內存模型與硬件內存架構的關係

由上可知,交叉訪問,導致數據不一致性。
4. Java內存模型的必要性
Java內存模型的作用:規範內存數據和工作空間數據的交互

併發編程的三個重要特性

  1. 原子性:不可分割 ,如轉賬操作,扣錢和加錢,要麼同時成功,要麼同時失敗。再如給x賦值爲1,x=1,那麼也爲原子性。
  2. 可見性:線程只能操作自己工作空間中的數據,不能操作其他工作空間的數據。操作內存中數據的時候,需要首先將內存中的數據讀取到自己的工作空間後進行操作。
  3. 有序性:但程序中的順序不一定就是執行的順序,如以下代碼的執行順序不一定按照編寫順序進行執行,會對程序進行重排,目的是爲了優化代碼,提高執行效率。
    int x = 1;
    int y = 2;
    int z = 3;
    z = x + y;
    System.out.println("hello");
    int m = 0;
    

關於重排,主要有2種:編譯重排、指令重排
重排的原則:

  • as-if-seria:不管怎麼重排序(編譯器和處理器爲了提高並行度),(單線程)程序的執行結果不會改變。編譯器和處理器不會對存在數據依賴關係的操作做重排序,因爲這種重排序會改變執行結果。但是,如果操作之間不存在數據依賴關係,這些操作就可能被編譯器和處理器重排序。如上述代碼,在不影響結果的情況下,CPU會優先執行耗時較少的讀操作,然後再執行寫操作。先執行x=1,y=2,z=3,m=0,然後再執行z=x+y。
  • 如果一個操作執行的結果需要對另一個操作可見,那麼這2個操作之間必須要存在happens-before關係。兩個操作之間具有happens-before關係,並不意味着前一個操作必須要在後一個操作之前執行!happens-before僅僅要求前一個操作(執行的結果)對後一個操作可見,且前一個操作按順序排在第二個操作之前。

JMM對三個特徵的保證

JMM與原子性

如果是私有數據具有原子性,如果是共享數據沒原子性(讀寫)

  • X=10 是一種寫操作, 具有原子性不可分割
  • Y=X 沒有原子性(分2步執行)
    1. 把數據X讀到工作空間(原子性)
    2. 把X的值寫到Y(原子性)
  • i++ 沒有原子性
    1. 讀i到工作空間
    2. +1;
    3. 刷新結果到內存
  • Z=Z+1 沒有原子性
    1. 讀z到工作空間
    2. +1;
    3. 刷新結果到內存

結論:多個原子性的操作合併到一起沒有原子性
保證方式:

  • Synchronized
  • JUC Lock的lock

JMM與可見性

  • Volatile:在JMM模型上實現MESI協議
  • Synchronized:加鎖
  • JUC Lock的lock

JMM與有序性

  • Volatile:位置不變
  • Synchronize:封鎖,位置不變
  • Happens-before原則:
    1. 程序次序原則
    2. 鎖定原則 :後一次加鎖必須等前一次解鎖
    3. Volatile原則:霸道原則
    4. 傳遞原則:A—B —C A–C
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章