1. 程式人生 > >Java千百問_07JVM架構(001)_java記憶體模型是什麼樣的

Java千百問_07JVM架構(001)_java記憶體模型是什麼樣的

1、什麼是記憶體模型

  Java平臺自動集成了執行緒以及多處理器技術,這種整合程度比Java以前誕生的計算機語言要厲害很多。Java針對多種異構平臺的獨立性,使得多執行緒技術也具有了開拓性的一面。
  
瞭解執行緒和程序看這裡:執行緒和程序有什麼區別

  我們有時候在Java開發中,對於同步和執行緒安全要求很嚴格的程式時,往往容易混淆的一個概念就是記憶體模型。那究竟什麼是記憶體模型呢?
  記憶體模型描述了程式中各個變數(例項域、靜態域和陣列元素)之間的關係,以及在實際計算機系統中將變數儲存到記憶體、從記憶體中取出變數這樣的底層細節。
  Java物件最終是儲存在記憶體裡面的,這點沒錯,但是編譯器、執行庫、處理器或者系統快取有權指定記憶體位置

來儲存或者取出變數的值。

2、記憶體模型有哪些規則

記憶體模型需要具有以下規則:原子性(Atomicity)可見性(Visibility)可排序性(Ordering)
1. 原子性(Atomicity)
原子性指的是原子級別的操作,比如最小的一塊記憶體的讀寫操作,可以理解為Java語言編譯過後最接近記憶體的最底層的操作單元。這種讀寫操作的資料單元不是變數的值,而是本機碼。

原子性規則約定了:訪問儲存單元內任何型別欄位的值以及對其更新操作時,除了long型別和double型別,其他型別的欄位是必須要保證其原子性的,這些欄位也包括為物件服務的引用。即,如果你獲得或者初始化某一些值時(這些值是由其他執行緒寫入的,而且不是從兩個或者多個執行緒在同一時間戳混合寫入的),該值的原子性在JVM內部是必須得到保證的

此外,原子性擴充套件規則可以延伸到基於long和double的另外兩種型別:volatile longvolatile double(volatile為java關鍵字),沒有被volatile宣告的long型別以及double型別的欄位值雖然不保證其JMM中的原子性,但是是被允許的。

只要在不違反該規則的情況下,JVM並不關心資料的值來自什麼執行緒,正這樣使得Java語言在並行運算的設計中,針對多執行緒的原子性設計變得極其簡單。即使開發人員沒有考慮到,最終的程式也沒有太大的影響。

2. 可見性(Visibility)
可見性指的是一個執行緒修改的狀態對另一個執行緒是可見的。也就是說一個執行緒修改的結果

,另一個執行緒馬上就能看到。比如:用volatile修飾的變數,就會具有可見性。volatile修飾的變數不允許執行緒內部快取和重排序,即直接修改記憶體,所以對其他執行緒是可見的。但是這裡需要注意一個問題,volatile只能讓被他修飾內容具有可見性,但不能保證它具有原子性。比如 volatile int a = 0;之後有一個操作a++;這個變數a具有可見性,但是a++依然是一個非原子操作,也就這這個操作同樣存線上程安全問題。

在可見性規則的約束下,定義了一個執行緒在哪種情況下可以訪問或者影響另外一個執行緒,以及從另外一個執行緒的可見區域讀取相關資料、將資料寫入到另外一個執行緒內。

3. 可排序性(Ordering)
可排序性是指為了提高效能,編譯器和處理器可能會對指令做重排序,包括:

  • 編譯器優化的重排序
    編譯器在不改變單執行緒程式語義的前提下,可以重新安排語句的執行順序。

  • 指令級並行的重排序
    現代處理器採用了指令級並行技術(Instruction-LevelParallelism,ILP)來將多條指令重疊執行。如果不存在資料依賴性,處理器可以改變語句對應機器指令的執行順序。

  • 記憶體系統的重排序
    由於處理器使用快取和讀/寫緩衝區,這使得載入和儲存操作看上去可能是在亂序執行。

volatile修飾的變數不允許執行緒內部快取和重排序。
可排序性規則將會約束任何一個違背了規則呼叫的執行緒在操作過程中的一些順序,排序問題主要圍繞了讀取、寫入和賦值語句有關的序列。

3、Java記憶體模型是什麼

JMM(Java記憶體模型,Java Memory Model的縮寫)是控制Java執行緒之間執行緒和主存之間通訊的協議。
JMM定義了執行緒和主記憶體之間的抽象關係:執行緒之間的共享變數儲存在主記憶體(main memory)中,每個執行緒都有一個私有的本地記憶體(local memory),本地記憶體中儲存了該執行緒以讀/寫共享變數的副本。本地記憶體是JMM的一個抽象概念,並不真實存在。它涵蓋了快取,寫緩衝區,暫存器以及其他的硬體和編譯器優化。
  JMM結構如下:
這裡寫圖片描述