Java內存模型(Java Memory Model,JMM)

今天簡單聊聊什麼叫做 Java 內存模型,不是 JVM 內存結構哦。

JMM 是一個語言級別的內存模型,處理器的硬件模型是硬件級別,Java中的內存模型是內存可見性的基本保證。從而爲我們 volatile 實現內存可見性提供了基石。主要目的就是讓 Java 程序員在各種平臺下達到一致性訪問效果

JMM決定一個線程對共享變量的寫入何時對另一個線程可見,尤其是在對共享變量的讀寫,修改後其他線程立刻內讀取到,這個就是JMM主要作用。從抽象的角度來看,JMM定義了線程和主內存之間的抽象關係:線程之間的共享變量存儲在主內存(Main Memory)中,每個線程都有一個私有的本地內存(Local Memory),本地內存中存儲了該線程以讀/寫共享變量的副本。本地內存是JMM的一個抽象概念,並不真實存在。它涵蓋了緩存、寫緩衝區、寄存器以及其他的硬件和編譯器優化。Java內存模型的抽象示意如圖所示。

image

前面我們說到 volatile 底層原理詳解,這個語義的實現就是利用了Java的內存模型。爲我們屏蔽了細節,實現了內存可見性,有興趣的讀者可以看公衆號前期發的文章 volatile 底層原理實現

爲什麼需要JMM?

1. 從源代碼到指令序列的重排序

在執行程序的時候,爲了提高性能,編譯器與處理器常會對指令進行重排序優化,保證執行結果與書序執行的結果是一致的,但並不能保證各個語句執行的先後順序與輸入的代碼順序一致。(當然是說在單線程的情況下)。

所以有 volatile 修飾的代碼就不會被指令重排,相當於加了一道內存屏障,不能把後面的指令重排序到內存屏障之前。

2. Happens-before原則(先行發生)

Happens-before定義:

  • 如果一個操作 Happens-before 另一個操作,那麼第一個操作的執行結果將對第二個操作可見,而且第一個操作的執行順序在第二個操作之前。
  • 兩個操作之間存在 Happens-before 關係,並不意味着必須按照代碼指定順序執行。如果重排序後的執行結果與按照 Happens-before 結果執行的結果一致,那也是可以的。

先行發生是 Java 內存模型中定義的兩項操作之間的偏序關係,如果說操作A先行發生於B,其實就是說在發生操作 B 之前,操作 A 產生的影響能被 B 觀察到, “影響” 包括修改了內存中共享變量的值、發送了消息、調用了方法。比如:

//在線程 A 執行  1
i =  2;`
// 在線程 B 執行   2
j = i;`
// 在線程 C 執行   3
i =  3;
  • 假設執行順序是 1 -> 3 -> 2:那麼 j 的值是 3。

  • 假設執行順序是 1 -> 2 -> 3:那麼 j 的值是 2。

若我們想要按照 1 ,2 ,3順序執行。那麼只有同步才能保證一致性。

總而言之:

  • 通過JMM內存模型,volatile 內存可見性的實現才得以保證。但是又不需要我們去關注不同平臺的細節。當對一個 volatile 修飾的變量修改是,JMM 會把該線程對應的本地內存中的共享變量刷新到主內存中。

  • 當讀一個 volatile 變量的時候, JMM 會把該線程對應的本地內存設置無效,並從主內存中讀取共享變量。

  • volatile 在滿足 Happens-before原則情況下,禁止指令重排序。

親愛的讀者朋友覺得文章不錯點贊或關注公衆號將是我最大的支持。歡迎關注公衆號獲取最新技術文章。
JavaStorm.png

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章