Java內存模型英文叫作(Java Memory Model),簡稱爲JMM。Java虛擬機規範試圖定義一種Java內存模型來屏蔽掉各類硬件和系統的內存訪問差別,實現平臺無關性。java
講JMM以前,咱們應該先了解下CPU和緩存一致性的問題。計算機在執行程序的時候,每條指令都是在CPU中執行的,而執行的時候,又要和數據打交道。而計算機上面的數據,是存放在內存當中的。隨着CPU的高速發展,從內存中讀取和寫入數據的過程和CPU的執行速度比起來差距就會愈來愈大,這致使了CPU不能滿負荷的工做,須要去等待數據從內存中讀取或者寫入。緩存
爲了解決內存和CPU速度不一致的問題,繼而引入了高速緩存這麼一個東西。在CPU和內存之間,放一個高速緩存做爲緩衝,這樣一來就提高了CPU的讀寫速度。安全
高速緩存解決了處理器和內存速度的矛盾,可是卻引入了另一個複雜的問題——緩存一致性。在多處理器系統中,每一個處理器都有本身的高速緩存,而內存又是各處理器共享的,這就可能致使各自的緩存數據不一致的狀況。多線程
爲了解決緩存一致性的問題,各個處理器訪問緩存時都遵循必定的協議,在讀寫時根據協議來操做,進而保證緩存的一致性。爲了保證共享內存的正確性(可見性、有序性、原子性),內存模型定義了共享內存系統中多線程程序讀寫操做行爲的規範。併發
Java虛擬機規範試圖定義一種Java內存模型來屏蔽掉各類硬件和系統的內存訪問差別,實現平臺無關性。其底層是根據不一樣系統的緩存讀寫協議分別進行處理的。開發者不用去關心各系統的差別,由於JVM已經幫咱們屏蔽了各系統的細節差別,咱們只須要關注JMM便可。spa
Java內存模型就是一種符合內存模型規範的,屏蔽了各類硬件和操做系統的訪問差別的,保證了Java程序在各類平臺下對內存的訪問都能保證效果一致的機制及規範。操作系統
Java內存模型定義了線程和主內存之間的抽象關係,Java各線程之間的通訊是有Java內存模型所控制的。從抽象來說,線程之間的共享變量存儲在主內存(main memory)中,每一個線程都有一個私有的工做內存(本地內存)(local memory),本地內存中存儲了該線程以讀 / 寫共享變量的副本。線程
Java內存模型裏所說的主內存,和工做內存(本地內存),都是抽象的概念,真實是不存在的,要區別於CPU高速緩存和內存設備。JMM只是JVM爲了屏蔽系統內存操做的差別所抽象出來的概念。code
Java內存模型規定了全部的變量都在主內存中,每條線程都有本身的工做內存。Java線程工做的時候,從主內存load數據到本身的工做內存中,這時工做內存就持有了主內存的一份數據拷貝。線程操做完以後,把數據從新save回主內存中。cdn
理解Java內存模型,是理解線程安全問題的基礎。知道JMM有主內存和工做內存之分以後,咱們就很容易的理解多個線程操做同個共享變量可能引起的數據不一致的問題。假設有以下代碼:
public class Main {
private static int a = 0;
public static void main(String[] args) throws InterruptedException {
for (int i = 0; i < 10000; i++) {
new Thread(() -> {
a = a+1;
}).start();
}
Thread.sleep(3000);
System.out.println(a);
}
}
複製代碼
這裏有一萬個線程去操做共享數據a,若是不存在併發問題的話,「預期的結果應該是10000」。執行程序,結果:
結果一:
結果二:
結果三:
實際的結果是無法預測的,理解了上面主內存和工做內存之分以後,相信你很快能理解其中的緣由。假設a等於0,同時存在兩個線程對其作了++操做,這時兩個工做內存的a都是1,回寫到主內存的時候也是1,「至關於少了一個1了」。
本文介紹了Java的內存模型,這裏須要強調的一點是,Java內存模型不一樣於Java內存結構,不要將兩者概念混淆。Java內存模型是爲了解決各線程之間的通訊所抽象出來的概念,Java內存結構則是Java中的數據存儲形式,也就是常常提到的堆內存、棧內存等。