java多執行緒:8、記憶體可見性前置知識
瞭解Java記憶體模型
JVM記憶體結構、Java物件模型和Java記憶體模型,這就是三個截然不同的概念,而這三個概念很容易混淆。這裡詳細區別一下
1 JVM記憶體結構
我們都知道,Java程式碼是要執行在虛擬機器上的,而虛擬機器在執行Java程式的過程中會把所管理的記憶體劃分為若干個不同的資料區域,這些區域都有各自的用途。其中有些區域隨著虛擬機器程序的啟動而存在,而有些區域則依賴使用者執行緒的啟動和結束而建立和銷燬。
在《Java虛擬機器規範(Java SE 8)》中描述了JVM執行時記憶體區域結構如下(五大區域):
各區域功能如下:
JVM記憶體結構,由Java虛擬機器規範定義。描述的是Java程式執行過程中,由JVM管理的不同資料區域。各個區域有其特定的功能。
2 Java物件模型
Java是一種面向物件的語言,而Java物件在JVM中的儲存也是有一定的結構的。而這個關於Java物件自身的儲存模型稱之為Java物件模型。
HotSpot虛擬機器中(Sun JDK和OpenJDK中所帶的虛擬機器,也是目前使用範圍最廣的Java虛擬機器),設計了一個OOP-Klass Model。OOP(Ordinary Object Pointer)指的是普通物件指標,而Klass用來描述物件例項的具體型別。
每一個Java類,在被JVM載入的時候,JVM會給這個類建立一個instanceKlass物件,儲存在方法區,用來在JVM層表示該Java類。當我們在Java程式碼中,使用new建立一個物件的時候,JVM會建立一個instanceOopDesc物件,這個物件中包含了物件頭以及例項資料。
這就是一個簡單的Java物件的OOP-Klass模型,即Java物件模型。
3 記憶體模型
Java 記憶體模型遮蔽了各種硬體和作業系統的訪問差異的,保證了Java程式在各種平臺下對記憶體的訪問都能保證效果一致的機制及規範。
有興趣詳細瞭解Java記憶體模型是什麼,為什麼要有Java記憶體模型,Java記憶體模型解決了什麼問題的學員,參考:https://www.hollischuang.com/archives/2550。
Java記憶體模型是根據英文Java Memory Model(JMM)翻譯過來的。其實JMM並不像JVM記憶體結構一樣是真實存在的。他只是一個抽象的概念。JSR-133: Java Memory Model and Thread Specification中描述了,JMM是和多執行緒相關的,他描述了一組規則或規範,這個規範定義了一個執行緒對共享變數的寫入時對另一個執行緒是可見的。
簡單總結下,Java的多執行緒之間是通過共享記憶體進行通訊的,而由於採用共享記憶體進行通訊,在通訊過程中會存在一系列如可見性、原子性、順序性等問題,而JMM就是圍繞著多執行緒通訊以及與其相關的一系列特性而建立的模型。JMM定義了一些語法集,這些語法集對映到Java語言中就是volatile、synchronized等關鍵字。
JMM執行緒操作記憶體的基本的規則:
第一條關於執行緒與主記憶體:執行緒對共享變數的所有操作都必須在自己的工作記憶體(本地記憶體)中進行,不能直接從主記憶體中讀寫
第二條關於執行緒間本地記憶體:不同執行緒之間無法直接訪問其他執行緒本地記憶體中的變數,執行緒間變數值的傳遞需要經過主記憶體來完成。
-
主記憶體
主要儲存的是Java例項物件,所有執行緒建立的例項物件都存放在主記憶體中,不管該例項物件是成員變數還是方法中的本地變數(也稱區域性變數),當然也包括了共享的類資訊、常量、靜態變數。由於是共享資料區域,多執行緒對同一個變數進行訪問可能會發現執行緒安全問題。 -
本地記憶體
主要儲存當前方法的所有本地變數資訊(本地記憶體中儲存著主記憶體中的變數副本拷貝),每個執行緒只能訪問自己的本地記憶體,即執行緒中的本地變數對其它執行緒是不可見的,就算是兩個執行緒執行的是同一段程式碼,它們也會各自在自己的工作記憶體中建立屬於當前執行緒的本地變數,當然也包括了位元組碼行號指示器、相關Native方法的資訊。注意由於工作記憶體是每個執行緒的私有資料,執行緒間無法相互訪問工作記憶體,因此儲存在工作記憶體的資料不存線上程安全問題。
4 小結
- JVM記憶體結構,和Java虛擬機器的執行時區域有關。
- Java物件模型,和Java物件在虛擬機器中的表現形式有關。
- Java記憶體模型,和Java的併發程式設計有關。