Java併發-JMM內存模型

1.線程與JVM
2.JVM內存模型與Java內存模型的區別
3.硬件內存架構與Java內存模型
4.Java內存模型對併發特徵的保證

一、基本概念

程序:代碼,完成某一件任務,代碼序列(靜態的概念)
進程:程序的一次運行(動態的概念)
線程:一個進程可能包含一個或多個線程(cpu分配資源的獨立單位)

二、JVM與線程

JVM什麼時候啓動?

答: java類被調用時

JVM線程 --> 其他的線程(main) 線程在jvm中

JVM內存區域
webp

方法區:
類的所有字段和方法字節碼,以及一些特殊方法如構造函數,接口代碼也在這裏定義。簡單來說,所有定義的方法的信息都保存在該區域,靜態變量+常量+類信息(構造方法/接口定義)+運行時常量池都存在方法區中,雖然Java虛擬機規範把方法區描述爲堆的一個邏輯部分,但是它卻有一個別名叫做(Non-Heap)非堆,目的應該爲了和Java的堆區分開(Jdk1.8以前hotspot虛擬機叫永久代,持久代,jdk時叫元空間)

堆:

  • 新生代(Young Generation)

    • 類出生、成長、消亡的區域,一個類在這裏產生,應用,最後被垃圾回收器回收,結束生命。
    • 新生代分爲兩個部分:
      • 伊甸區(Eden space)和倖存者區(Survivor space),所有的類都是在Eden space被new出來的。倖存區又分爲From區和To區。當Eden區的空間用完時,程序又需要創建新的對象,JVM的垃圾回收器將Eden區進行垃圾回收(Minior GC),將Eden區中不再被其它對象引用的對象進行銷燬。然後將Eden區中剩餘的對象移到From Surivor區。如From Survior區也滿了,再對該區進行垃圾回收,然後移動到To Survior區。
  • 老年代

    • 新生代經過多次GC仍然存活的對象移動到老年區,若老年代也滿了,這時候發生Major GC(也可以叫 Full GC),進行老年區的內存清理。若老年區執行了Full GC之後依然無法進行對象的保存,就會拋出OOM(OutOfMemoryError) 異常。
  • 元空間

    • 在jdk1.8以後,元空間替代了永久代,它是對JVM規範中方法區的實現,區別在於元數據區不再虛擬機中,而是用的本地內存,永久代在虛擬機中,永久代的邏輯結構上也屬於堆,但是物理上不屬於。
    • 爲什麼移除永久代?
      • 參考官方解釋:http://openjdk.java.net/jeps/122
      • 大概意思是移除永久代是爲融合HotSpot與 JRockit而做出的努力,因爲JRockit沒有永久代,不需要配置永久代。

虛擬機棧:
Java線程執行方法的內存模型,一個線程對應一個棧,每個方法在執行的同時都會創建一個棧幀(用於存儲局部變量表,操作數棧,動態鏈接,方法出口等信息)不存在垃圾回收問題,只要線程一結束該棧就會釋放,生命週期和線程一致

本地方法棧:
跟虛擬機的差不多

程序計算器:
就是一個指針,指向方法區中的方法字節碼(用來存儲指向下一條指令的地址,也即將要執行的指令代碼),由執行引擎讀取下一條指令,是一個非常的小的內存空間,幾乎可以忽略不計。

三、Java內存模型

全稱 Java Memory model

webp

JMM定義了Java 虛擬機(JVM)在計算機內存(RAM)中的工作方式。JVM是整個計算機虛擬模型,所以JMM是隸屬於JVM的。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(Main Memory)中,每個線程都有一個私有的本地內存(Local Memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存、寫緩衝區、寄存器以及其他的硬件和編譯器優化。

主內存:線程共享的內存

工作內存:私有信息,基本的數據類型,直接分配到工作內存,引用的地址存放在工作內存,引用的對象放在堆中。

工作方式:

  • 1.線程修改私有數據,直接在工作空間修改
  • 2.線程修改共享數據,把數據copy到工作空間去,在工作空間修改,修改完成之後,在刷新到內存中去。

四、硬件內存與Java內存模型

硬件內存架構

webp

該內存架構帶來的問題:

1.CPU緩存的一致性問題:併發處理的不同步
2.解決方案:

  • 總線加鎖 缺點:降低CPU的吞吐量
  • 緩存上的一致性協議(MESI)
    • 當cpu在cache中操作數據時,如果該數據是共享變量,數據在cache讀到CPU的寄存器中,進行新修改,並更新內存數據cache, LINE置無效,其他的cpu就從內存中讀數據。

五、Java內存模型的必要性

java內存模型的作用:規範內存數據和工作空間數據的交互

六、併發編程的三個重要特性

  1. 原子性:不可分割 x=1
  2. 可見性:線程只能操作自己工作空間中的數據
  3. 有序性:程序中的順序不一定就是執行的順序

編譯重排序,指令重排序,提高效率

as-if seria:單線程中重排後不影響執行的結果

多線程:
happens-before

JMM對三個特性的保證

1.JMM與原子性

  • a. X=10 寫 原子性 如果是私有數據具有原子性,如果是共享數據沒原子性(讀寫)

  • b. 表達式:y=x 沒有原子性

    • 把數據X讀到工作空間(原子性)
    • 把X的值寫到Y(原子性)
  • c. i++ 表達式 沒有原子性

    • 讀i到工作空間
    • +1;
    • 刷新結果到內存

多個原子性的操作合併到一起沒有原子性
保證方式:
synchronized關鍵字,JUC Lock的lock

  1. JMM與可見性

volatile關鍵字 在JMM 模型實現MESI協議
synchronized 加鎖
JUC Lock的lock

  1. JMM與有序性

volatile關鍵字
synchronized關鍵字

happens-before原則:

  • 程序的次序原則
  • 鎖定原則:後一次加鎖必須等前一次解鎖
  • volatile原則:不允許重排序
  • 傳遞原則:A–B—C 推導 A – C

參考文章:
深入理解JVM-內存模型(jmm)和GC - 簡書

併發概念模型:JMM(JAVA內存模型) - Dorami - 博客園

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章