Java 内存模型(Java Memory Model)
一、概述
Java 內存模型(簡稱 JMM):定義了線程和主內存之間的抽象關系,即 JMM 定義了 JVM 在計算機內存(RAM)中的工作方式。
其和內存區域是不一樣的東西。內存區域是指 JVM 運行時將數據分區域存儲,強調對內存空間的劃分,即運行時數據區(Runtime Data Area)。
二、Java 內存模型
JMM 是共享內存的并發模型,線程之間主要通過讀-寫共享變量(堆內存中的實例域,靜態域和數組元素)來完成隱式通信。JMM 控制 Java 線程之間的通信,決定一個線程對共享變量的寫入何時對另一個線程可見。
三、計算機高速緩存和緩存一致性
計算機在高速的 CPU 和相對低速的存儲設備之間使用高速緩存,作為內存和處理器之間的緩沖。將運算需要使用到的數據復制到緩存中,讓運算能快速運行,當運算結束后再從緩存同步回內存之中。
在多處理器的系統中(或者單處理器多核的系統),每個處理器內核都有自己的高速緩存,它們共享同一主內存(Main Memory)。當多個處理器的運算任務都涉及同一塊主內存區域時,將可能導致各自的緩存數據不一致。
為此,需要各個處理器訪問緩存時都遵循一些協議,在讀寫時要根據協議進行操作,來維護緩存的一致性。
四、JVM 主內存與工作內存
Java 內存模型的主要目標是定義程序中各個變量的訪問規則,即在虛擬機中將變量(線程共享的變量)存儲到內存和從內存中取出變量這樣底層細節。
Java 內存模型中規定了所有的變量都存儲在主內存中,每條線程有自己的工作內存。線程對變量的所有操作都必須在工作內存中進行,而不能直接讀寫主內存中的變量。
這里的工作內存是 JMM 的一個抽象概念,也叫本地內存,其存儲了該線程讀/寫共享變量的副本。就像每個處理器內核擁有私有的高速緩存,JMM 中每個線程擁有私有的本地內存。
不同線程之間無法直接訪問對方工作內存中的變量,線程間的通信一般有兩種方式進行,一是通過消息傳遞,二是共享內存。Java 線程間的通信采用的是共享內存方式,線程、主內存和工作內存的交互關系如圖:
這里所講的主內存、工作內存與 Java 內存區域中的 Java 堆、棧、方法區等并不是同一個層次的內存劃分,這兩者基本上是沒有關系的,如果兩者一定要勉強對應起來,那從變量、主內存、工作內存的定義來看,主內存主要對應于 Java 堆中的對象實例數據部分,而工作內存則對應于虛擬機棧中的部分區域。
五、重排序和 happens-before 規則
在執行程序時為了提高性能,編譯器和處理器常常會對指令做重排序。重排序分三種類型:
從 Java 源代碼到最終實際執行的指令序列,會分別經歷下面三種重排序:
JMM 屬于語言級的內存模型,它確保在不同的編譯器和不同的處理器平臺之上,通過禁止特定類型的編譯器重排序和處理器重排序,為程序員提供一致的內存可見性保證。
Java 編譯器禁止處理器重排序是通過在生成指令序列的適當位置會插入內存屏障(重排序時不能把后面的指令重排序到內存屏障之前的位置)指令來實現的。
happens-before
從JDK5開始,Java 內存模型提出了 happens-before 的概念,通過這個概念來闡述操作之間的內存可見性。
如果一個操作執行的結果需要對另一個操作可見這里的“可見”是指當一條線程修改了某個變量的值,新值對于其他線程來說是可以立即得知的,那么這兩個操作之間必須存在 happens-before 關系。這里提到的兩個操作既可以是在一個線程之內,也可以是在不同線程之間。
如果甲 happens-before 乙,那么 Java 內存模型將向程序員保證甲操作的結果將對乙可見,且甲的執行順序排在乙之前。
重要的 happens-before 規則如下:
如圖是 happens-before 與 JMM 的關系:
總結
以上是生活随笔為你收集整理的Java 内存模型(Java Memory Model)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 借口很多呀嘛接口也很多呀嘛态也很多
- 下一篇: 我的学习生涯(Delphi篇) - 21