Java-內(nèi)存模型知識

Java內(nèi)存模型的抽象結(jié)構(gòu)

一、 運(yùn)行時內(nèi)存的劃分

先談一下運(yùn)行時數(shù)據(jù)區(qū),下面這張圖相信大家一點(diǎn)都不陌生:


對于每一個線程來說,棧都是私有的,而堆是共有的。

也就是說在棧中的變量(局部變量、方法定義參數(shù)、異常處理器參數(shù))不會在線程之間共享,也就不會有內(nèi)存可見性(下文會說到)的問題,也不受內(nèi)存模型的影響。而在堆中的變量是共享的,本文稱為共享變量。

所以,內(nèi)存可見性是針對的共享變量

二、既然堆是共享的,為什么在堆中會有內(nèi)存不可見問題?

這是因?yàn)楝F(xiàn)代計算機(jī)為了高效,往往會在高速緩存區(qū)中緩存共享變量,因?yàn)閏pu訪問緩存區(qū)比訪問內(nèi)存要快得多。

線程之間的共享變量存在主內(nèi)存中,每個線程都有一個私有的本地內(nèi)存,存儲了該線程以讀、寫共享變量的副本。本地內(nèi)存是Java內(nèi)存模型的一個抽象概念,并不真實(shí)存在。它涵蓋了緩存、寫緩沖區(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)存中進(jìn)行,不能直接從主內(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)存屏障來實(shí)現(xiàn)內(nèi)存的可見性以及禁止重排序。為了程序員的方便理解,提出了happens-before,它更加的簡單易懂,從而避免了程序員為了理解內(nèi)存可見性而去學(xué)習(xí)復(fù)雜的重排序規(guī)則以及這些規(guī)則的具體實(shí)現(xiàn)方法。

三、JMM與Java內(nèi)存區(qū)域劃分的區(qū)別與聯(lián)系

上面兩小節(jié)分別提到了JMM和Java運(yùn)行時內(nèi)存區(qū)域的劃分,這兩者既有差別又有聯(lián)系:

  • 區(qū)別

    兩者是不同的概念層次。JMM是抽象的,他是用來描述一組規(guī)則,通過這個規(guī)則來控制各個變量的訪問方式,圍繞原子性、有序性、可見性等展開的。而Java運(yùn)行時內(nèi)存的劃分是具體的,是JVM運(yùn)行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ù)器、本地方法棧、虛擬機(jī)棧。

實(shí)際上,他們表達(dá)的是同一種含義,這里不做區(qū)分。

更多詳細(xì)關(guān)于JMM的知識的可參考:
JVM—認(rèn)識JVM的內(nèi)存布局和運(yùn)行時數(shù)據(jù)區(qū)
Java內(nèi)存模型(JMM)詳解,java語言入門知識

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容