前面介紹了計(jì)算機(jī)內(nèi)存模型,這是解決多線程場(chǎng)景下并發(fā)問題的一個(gè)重要規(guī)范。
那么具體的實(shí)現(xiàn)是如何的呢?不同的編程語(yǔ)言,在實(shí)現(xiàn)上可能有所不同。
我們知道,Java 程序是需要運(yùn)行在 Java 虛擬機(jī)上面的,Java 內(nèi)存模型(Java Memory Model,JMM)就是一種符合內(nèi)存模型規(guī)范的,屏蔽了各種硬件和操作系統(tǒng)的訪問差異的,保證了Java 程序在各種平臺(tái)下對(duì)內(nèi)存的訪問都能保證效果一致的機(jī)制及規(guī)范。
提到 Java 內(nèi)存模型,一般指的是 JDK 5 開始使用的新內(nèi)存模型,主要由 JSR-133:JavaTM Memory Model and Thread Specification 描述。
Java 內(nèi)存模型規(guī)定了所有的變量都存儲(chǔ)在主內(nèi)存中,每條線程還有自己的工作內(nèi)存。
線程的工作內(nèi)存中保存了該線程中用到的變量的主內(nèi)存副本拷貝,線程對(duì)變量的所有操作都必須在工作內(nèi)存中進(jìn)行,而不能直接讀寫主內(nèi)存。
不同的線程之間也無(wú)法直接訪問對(duì)方工作內(nèi)存中的變量,線程間變量的傳遞均需要自己的工作內(nèi)存和主存之間進(jìn)行數(shù)據(jù)同步進(jìn)行。
而 JMM 就作用于工作內(nèi)存和主存之間數(shù)據(jù)同步過程。它規(guī)定了如何做數(shù)據(jù)同步以及什么時(shí)候做數(shù)據(jù)同步。
這里面提到的主內(nèi)存和工作內(nèi)存,讀者可以簡(jiǎn)單的類比成計(jì)算機(jī)內(nèi)存模型中的主存和緩存的概念。
特別需要注意的是,主內(nèi)存和工作內(nèi)存與 JVM 內(nèi)存結(jié)構(gòu)中的 Java 堆、棧、方法區(qū)等并不是同一個(gè)層次的內(nèi)存劃分,無(wú)法直接類比。
《深入理解Java虛擬機(jī)》中認(rèn)為:如果一定要勉強(qiáng)對(duì)應(yīng)起來的話,從變量、主內(nèi)存、工作內(nèi)存的定義來看,主內(nèi)存主要對(duì)應(yīng)于 Java 堆中的對(duì)象實(shí)例數(shù)據(jù)部分。而工作內(nèi)存則對(duì)應(yīng)于虛擬機(jī)棧中的部分區(qū)域。
所以,再來總結(jié)下,JMM 是一種規(guī)范,是解決由于多線程通過共享內(nèi)存進(jìn)行通信時(shí),存在的本地內(nèi)存數(shù)據(jù)不一致、編譯器會(huì)對(duì)代碼指令重排序、處理器會(huì)對(duì)代碼亂序執(zhí)行等帶來的問題。
目的是保證并發(fā)編程場(chǎng)景中的原子性、可見性和有序性。
Java 內(nèi)存模型的實(shí)現(xiàn)
了解 Java 多線程的朋友都知道,在 Java 中提供了一系列和并發(fā)處理相關(guān)的關(guān)鍵字,比如 Volatile、Synchronized、Final、Concurren 包等。
其實(shí)這些就是 Java 內(nèi)存模型封裝了底層的實(shí)現(xiàn)后提供給程序員使用的一些關(guān)鍵字。
在開發(fā)多線程的代碼的時(shí)候,我們可以直接使用 Synchronized 等關(guān)鍵字來控制并發(fā),這樣就不需要關(guān)心底層的編譯器優(yōu)化、緩存一致性等問題。
所以,Java 內(nèi)存模型,除了定義了一套規(guī)范,還提供了一系列原語(yǔ),封裝了底層實(shí)現(xiàn)后,供開發(fā)者直接使用。