基本概念
程序
代碼,完成某一任務的代碼序列(靜態的概念)
進程
程序在某些數據上的一次運行,有開始、有結束、有生命週期(動態的概念)
線程
一個進程包含一個或多個線程,佔有該資源(內存、CPU等)的獨立單元(微觀的概念)
JVM與線程
JVM什麼時候啓動 :Java程序類被調用的時候,JVM線程會啓動,然後再啓動其他線程(如:main)
JVM內存區域
JVM內存區域是人爲劃分的區域,實際的物理區域並不會如此劃分的。
- 方法區:類信息、常量、static、JIT(即時編譯) ,如常用的反射加載。(信息共享)
- 堆區域:實例對象 GC(垃圾回收)工作的主要對象。(信息共享、OOM內存溢出)
- VM stack(棧):Java方法運行的內存模型(OOM內存溢出)。如下:
- PC:Java線程的私有數據,這個數據就是執行下一條指令的地址。
- native method stack:線程私有的區域 ,與虛擬機 jvm的native方法有關,一般情況下我們編碼開發過程中是不關心。
JVM內存模型
Java Memory Model(JMM),是一種規範,是一種抽象的模型。
- 主內存:共享的信息
- 工作內存:私有信息,如果是基本數據類型,直接分配到工作內存;如果是引用的地址,存放在工作內存;如果是引用的對象,那麼存放在堆中
- 工作方式:
A)線程修改私有數據,直接在工作空間修改
B)線程修改共享數據,把數據複製到工作空間中去,在工作空間中修改,修改完成以後,刷新內存中的數據。有可能存在線程不安全(不一致性)
其中,JVM內存區域劃分就是根據JVM的內存模型(JMM)來進行實現的。JMM是模型,JVM內存區域是實現方案。工作內存對應的VM Stack,存儲私有信息,方法區和堆對應的主內存,可以進行信息共享。
硬件內存架構與Java內存模型
- 硬件架構
- CPU緩存的一致性問題:併發處理的不同步,如內存中的變量X=1,CPU1修改X=2,此時CPU2讀取X的值,那麼CPU2讀取的X的值有可能爲1(由於併發處理,此時Cache中的2還未同步到內存中),也有可能爲2.
- 解決方案:
- 總線(BUS)加鎖、 降低CPU的吞吐量,但也降低了CPU的處理能力
- 緩存上的一致性協議(MESI)
當CPU在Cache中操作數據時,如果該數據是共享變量,數據在CACHE讀到寄存器中,進行新修改,並更新內存數據
CacheLINE(信號線)置無效,其他的CPU就不從Cache中讀取,而從內存中去讀數據。
- Java線程與硬件處理器
- Java內存模型與硬件內存架構的關係
由上可知,交叉訪問,導致數據不一致性。
4. Java內存模型的必要性
Java內存模型的作用:規範內存數據和工作空間數據的交互
併發編程的三個重要特性
- 原子性:不可分割 ,如轉賬操作,扣錢和加錢,要麼同時成功,要麼同時失敗。再如給x賦值爲1,x=1,那麼也爲原子性。
- 可見性:線程只能操作自己工作空間中的數據,不能操作其他工作空間的數據。操作內存中數據的時候,需要首先將內存中的數據讀取到自己的工作空間後進行操作。
- 有序性:但程序中的順序不一定就是執行的順序,如以下代碼的執行順序不一定按照編寫順序進行執行,會對程序進行重排,目的是爲了優化代碼,提高執行效率。
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步執行)
- 把數據X讀到工作空間(原子性)
- 把X的值寫到Y(原子性)
- i++ 沒有原子性
- 讀i到工作空間
- +1;
- 刷新結果到內存
- Z=Z+1 沒有原子性
- 讀z到工作空間
- +1;
- 刷新結果到內存
結論:多個原子性的操作合併到一起沒有原子性
保證方式:
- Synchronized
- JUC Lock的lock
JMM與可見性
- Volatile:在JMM模型上實現MESI協議
- Synchronized:加鎖
- JUC Lock的lock
JMM與有序性
- Volatile:位置不變
- Synchronize:封鎖,位置不變
- Happens-before原則:
- 程序次序原則
- 鎖定原則 :後一次加鎖必須等前一次解鎖
- Volatile原則:霸道原則
- 傳遞原則:A—B —C A–C