Java 內存模型是根據英文Java Memory Model(JMM)翻譯過來的。其實JMM並不像JVM內存結構同樣是真實存在的。他只是一個抽象的概念。用於屏蔽掉各類硬件和操做系統的內存訪問差別,以實現讓 Java 程序在各類平臺下都能達到一致的併發效果。html
在 Java 面試中,通常會問 Java 內存模型,本篇將揭開 Java 內存模型神祕的面紗。java
併發編程要解決的關鍵問題:程序員
通訊是指線程之間以何種機制進行交換信息。在命令行編程中,線程之間的通訊機制有兩種:共享內存和消息傳遞 。在共享內存模型中,線程之間共享程序的公共狀態,經過寫 - 讀內存中的公共狀態進行隱式通訊。在消息傳遞的併發模型中,線程之間沒有公共狀態,線程之間必須經過發送消息顯式進行通訊。面試
同步是指程序中控制不一樣線程間操做發生相對順序的機制。在共享內存併發模型裏,同步時顯式進行的。編程
Java 的併發採用的是共享內存模型,Java 線程之間的通訊老是隱式進行,整個通訊過程是徹底透明的。數組
Java 把內存分爲兩個部分:緩存
Java 內存模型規定了全部的變量都存儲在主內存中,每條線程還有本身的工做內存,線程的工做內存中保存了該線程中是用到的變量的主內存副本拷貝,線程對變量的全部操做都必須在工做內存中進行,而不能直接讀寫主內存。不一樣的線程之間也沒法直接訪問對方工做內存中的變量,線程間變量的傳遞均須要本身的工做內存和主存之間進行數據同步進行。多線程
而 JMM 就做用於工做內存和主存之間數據同步過程。他規定了如何作數據同步以及何時作數據同步。併發
在Java中提供了一系列和併發處理相關的關鍵字,好比 volatile
、synchronized
、final
、concurren
包等。其實這些就是Java內存模型封裝了底層的實現後提供給程序員使用的一些關鍵字。oracle
在開發多線程的代碼的時候,咱們能夠直接使用 synchronized
等關鍵字來控制併發,歷來就不須要關心底層的編譯器優化、緩存一致性等問題。因此,Java 內存模型,除了定義了一套規範,還提供了一系列原語,封裝了底層實現後,供開發者直接使用。
面試中,面試官問我Java內存模型,我說成了 JVM 內存結構,不少人都把這概念搞混了,其實徹底不同,因此這裏也講講 JVM 內存結構。
在《Java虛擬機規範(Java SE 8)》中描述了JVM運行時內存區域結構以下:
以上是Java虛擬機規範,不一樣的虛擬機實現會各有不一樣,可是通常會遵照規範
規範中定義的方法區,只是一種概念上的區域,並說明了其應該具備什麼功能。可是並無規定這個區域到底應該處於何處。因此,對於不一樣的虛擬機實現來講,是由必定的自由度的。
不一樣版本的方法區所處位置不一樣,上圖中劃分的是邏輯區域,並非絕對意義上的物理區域。由於某些版本的JDK中方法區實際上是在堆中實現的
運行時常量池用於存放編譯期生成的各類字面量和符號應用。可是,Java語言並不要求常量只有在編譯期才能產生。好比在運行期,String.intern也會把新的常量放入池中。
除了以上介紹的JVM運行時內存外,還有一塊內存區域可供使用,那就是直接內存。Java虛擬機規範並無定義這塊內存區域,因此他並不禁JVM管理,是利用本地方法庫直接在堆外申請的內存區域。
堆和棧的數據劃分也不是絕對的,如HotSpot的JIT會針對對象分配作相應的優化。
詳細的對比能夠參考:JVM內存結構 VS Java內存模型 VS Java對象模型
JMM 是一種規範,目的是解決因爲多線程經過共享內存進行通訊時,存在的本地內存數據不一致、編譯器會對代碼指令重排序、處理器會對代碼亂序執行等帶來的問題。對於 JMM 設計的關鍵字,後續文章會有部分講解。