Java內(nèi)存模型的抽象結(jié)構(gòu)
一棘催、 運行時內(nèi)存的劃分
先談一下運行時數(shù)據(jù)區(qū),下面這張圖相信大家一點都不陌生:
對于每一個線程來說倍宾,棧都是私有的雏节,而堆是共有的。
也就是說在棧中的變量(局部變量高职、方法定義參數(shù)钩乍、異常處理器參數(shù))不會在線程之間共享,也就不會有內(nèi)存可見性(下文會說到)的問題怔锌,也不受內(nèi)存模型的影響寥粹。而在堆中的變量是共享的,本文稱為共享變量埃元。
所以涝涤,內(nèi)存可見性是針對的共享變量。
二岛杀、既然堆是共享的阔拳,為什么在堆中會有內(nèi)存不可見問題?
這是因為現(xiàn)代計算機為了高效类嗤,往往會在高速緩存區(qū)中緩存共享變量糊肠,因為cpu訪問緩存區(qū)比訪問內(nèi)存要快得多辨宠。
線程之間的共享變量存在主內(nèi)存中,每個線程都有一個私有的本地內(nèi)存货裹,存儲了該線程以讀嗤形、寫共享變量的副本。本地內(nèi)存是Java內(nèi)存模型的一個抽象概念弧圆,并不真實存在赋兵。它涵蓋了緩存、寫緩沖區(qū)搔预、寄存器等霹期。
Java線程之間的通信由Java內(nèi)存模型(簡稱JMM)控制,從抽象的角度來說斯撮,JMM定義了線程和主內(nèi)存之間的抽象關(guān)系经伙。JMM的抽象示意圖如圖所示:
從圖中可以看出: 1. 所有的共享變量都存在主內(nèi)存中扶叉。 2. 每個線程都保存了一份該線程使用到的共享變量的副本勿锅。 3. 如果線程A與線程B之間要通信的話,必須經(jīng)歷下面2個步驟: 1. 線程A將本地內(nèi)存A中更新過的共享變量刷新到主內(nèi)存中去枣氧。 2. 線程B到主內(nèi)存中去讀取線程A之前已經(jīng)更新過的共享變量溢十。
所以,線程A無法直接訪問線程B的工作內(nèi)存达吞,線程間通信必須經(jīng)過主內(nèi)存张弛。
注意,根據(jù)JMM的規(guī)定酪劫,線程對共享變量的所有操作都必須在自己的本地內(nèi)存中進行吞鸭,不能直接從主內(nèi)存中讀取。
所以線程B并不是直接去主內(nèi)存中讀取共享變量的值覆糟,而是先在本地內(nèi)存B中找到這個共享變量刻剥,發(fā)現(xiàn)這個共享變量已經(jīng)被更新了,然后本地內(nèi)存B去主內(nèi)存中讀取這個共享變量的新值滩字,并拷貝到本地內(nèi)存B中造虏,最后線程B再讀取本地內(nèi)存B中的新值。
那么怎么知道這個共享變量的被其他線程更新了呢麦箍?這就是JMM的功勞了漓藕,也是JMM存在的必要性之一。JMM通過控制主內(nèi)存與每個線程的本地內(nèi)存之間的交互挟裂,來提供內(nèi)存可見性保證享钞。
Java中的volatile關(guān)鍵字可以保證多線程操作共享變量的可見性以及禁止指令重排序,synchronized關(guān)鍵字不僅保證可見性诀蓉,同時也保證了原子性(互斥性)栗竖。在更底層寝姿,JMM通過內(nèi)存屏障來實現(xiàn)內(nèi)存的可見性以及禁止重排序。為了程序員的方便理解划滋,提出了happens-before饵筑,它更加的簡單易懂,從而避免了程序員為了理解內(nèi)存可見性而去學(xué)習(xí)復(fù)雜的重排序規(guī)則以及這些規(guī)則的具體實現(xiàn)方法处坪。
三根资、JMM與Java內(nèi)存區(qū)域劃分的區(qū)別與聯(lián)系
上面兩小節(jié)分別提到了JMM和Java運行時內(nèi)存區(qū)域的劃分,這兩者既有差別又有聯(lián)系:
-
區(qū)別
兩者是不同的概念層次同窘。JMM是抽象的玄帕,他是用來描述一組規(guī)則,通過這個規(guī)則來控制各個變量的訪問方式想邦,圍繞原子性裤纹、有序性、可見性等展開的丧没。而Java運行時內(nèi)存的劃分是具體的鹰椒,是JVM運行Java程序時,必要的內(nèi)存劃分呕童。
-
聯(lián)系
都存在私有數(shù)據(jù)區(qū)域和共享數(shù)據(jù)區(qū)域漆际。一般來說,JMM中的主內(nèi)存屬于共享數(shù)據(jù)區(qū)域夺饲,他是包含了堆和方法區(qū)奸汇;同樣,JMM中的本地內(nèi)存屬于私有數(shù)據(jù)區(qū)域往声,包含了程序計數(shù)器擂找、本地方法棧、虛擬機棧浩销。
實際上贯涎,他們表達的是同一種含義,這里不做區(qū)分撼嗓。
更多詳細關(guān)于JMM的知識的可參考:
JVM—認(rèn)識JVM的內(nèi)存布局和運行時數(shù)據(jù)區(qū)
Java內(nèi)存模型(JMM)詳解柬采,java語言入門知識