1.線程與JVM
2.JVM內存模型與Java內存模型的區別
3.硬件內存架構與Java內存模型
4.Java內存模型對併發特徵的保證
一、基本概念
程序:代碼,完成某一件任務,代碼序列(靜態的概念)
進程:程序的一次運行(動態的概念)
線程:一個進程可能包含一個或多個線程(cpu分配資源的獨立單位)
二、JVM與線程
JVM什麼時候啓動?
答: java類被調用時
JVM線程 --> 其他的線程(main) 線程在jvm中
JVM內存區域
方法區:
類的所有字段和方法字節碼,以及一些特殊方法如構造函數,接口代碼也在這裏定義。簡單來說,所有定義的方法的信息都保存在該區域,靜態變量+常量+類信息(構造方法/接口定義)+運行時常量池都存在方法區中,雖然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
JMM定義了Java 虛擬機(JVM)在計算機內存(RAM)中的工作方式。JVM是整個計算機虛擬模型,所以JMM是隸屬於JVM的。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(Main Memory)中,每個線程都有一個私有的本地內存(Local Memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存、寫緩衝區、寄存器以及其他的硬件和編譯器優化。
主內存:線程共享的內存
工作內存:私有信息,基本的數據類型,直接分配到工作內存,引用的地址存放在工作內存,引用的對象放在堆中。
工作方式:
- 1.線程修改私有數據,直接在工作空間修改
- 2.線程修改共享數據,把數據copy到工作空間去,在工作空間修改,修改完成之後,在刷新到內存中去。
四、硬件內存與Java內存模型
硬件內存架構
該內存架構帶來的問題:
1.CPU緩存的一致性問題:併發處理的不同步
2.解決方案:
- 總線加鎖 缺點:降低CPU的吞吐量
- 緩存上的一致性協議(MESI)
- 當cpu在cache中操作數據時,如果該數據是共享變量,數據在cache讀到CPU的寄存器中,進行新修改,並更新內存數據cache, LINE置無效,其他的cpu就從內存中讀數據。
五、Java內存模型的必要性
java內存模型的作用:規範內存數據和工作空間數據的交互
六、併發編程的三個重要特性
- 原子性:不可分割 x=1
- 可見性:線程只能操作自己工作空間中的數據
- 有序性:程序中的順序不一定就是執行的順序
編譯重排序,指令重排序,提高效率
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
- JMM與可見性
volatile關鍵字 在JMM 模型實現MESI協議
synchronized 加鎖
JUC Lock的lock
- JMM與有序性
volatile關鍵字
synchronized關鍵字
happens-before原則:
- 程序的次序原則
- 鎖定原則:後一次加鎖必須等前一次解鎖
- volatile原則:不允許重排序
- 傳遞原則:A–B—C 推導 A – C