溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java的內(nèi)存模型的應(yīng)用

發(fā)布時間:2021-08-31 16:33:07 來源:億速云 閱讀:105 作者:chen 欄目:大數(shù)據(jù)

本篇內(nèi)容介紹了“Java的內(nèi)存模型的應(yīng)用”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

首先給出定義,Java內(nèi)存模型(Java Memory Model ,JMM)是一種符合內(nèi)存模型規(guī)范的,屏蔽了各種硬件和操作系統(tǒng)的訪問差異的,保證了Java程序在各種平臺下對內(nèi)存的訪問都能保證效果一致的機(jī)制及規(guī)范。

在弄懂JMM之前,我們要先了解下CPU和內(nèi)存是如何交互的。

CPU和高速緩存以及內(nèi)存(主存)的交互

Java的內(nèi)存模型的應(yīng)用
從圖中可以看出在多CPU的系統(tǒng)中,每個CPU都有都有各自的高速緩存,一般分為L1L2、L3緩存,因為這些緩存的存在,提供了數(shù)據(jù)的訪問性能,也減輕了數(shù)據(jù)總線上數(shù)據(jù)傳輸?shù)膲毫Γ鲀?nèi)存卻只有一個 。
CPU要讀取一個數(shù)據(jù)時,首先從一級緩存中查找,如果沒有找到再從二級緩存中查找,如果還是沒有就從三級緩存或內(nèi)存中查找,每個CPU有且只有一套自己的緩存。

但是問題也就來了,如果兩個CPU同時去操作同一個內(nèi)存地址,會發(fā)生什么?也就是說,如何保證多個處理器運(yùn)算涉及到同一個內(nèi)存區(qū)域時,多線程場景下的緩存一致性問題?運(yùn)行時如何保證數(shù)據(jù)一致性?那就是內(nèi)存屏障(Memory Barrier)。

內(nèi)存屏障

CPU中的高速緩存提高了數(shù)據(jù)訪問性能,避免每次都向內(nèi)存索取,但是不能實時的和內(nèi)存發(fā)生信息交換。在不同CPU執(zhí)行的不同線程對同一個變量的緩存值可能是不同的,由此就出現(xiàn)了內(nèi)存屏障,硬件層的內(nèi)存屏障分為兩種:Load BarrierStore Barrier即讀屏障和寫屏障。

內(nèi)存屏障的作用主要有兩點:

  • 阻止屏障兩側(cè)指令重排序

  • 強(qiáng)制把寫緩沖區(qū)/高速緩存中的臟數(shù)據(jù)等寫回主內(nèi)存,讓緩存中相應(yīng)的數(shù)據(jù)失效。

之所以扯了那么多計算機(jī)內(nèi)存模型,是因為Java內(nèi)存模型的設(shè)定符合了計算機(jī)的規(guī)范。

實際上,JMMJVM的一種規(guī)范,定義了JVM的內(nèi)存模型。
它屏蔽了各種硬件和操作系統(tǒng)的訪問差異,不像C那樣直接訪問硬件內(nèi)存,相對安全很多。
它的主要目的是解決由于多線程通過共享內(nèi)存進(jìn)行通信時,存在的本地內(nèi)存數(shù)據(jù)不一致、編譯器會對代碼指令重排序、處理器會對代碼亂序執(zhí)行等帶來的問題??梢员WC并發(fā)編程場景中的原子性、可見性和有序性。

Java內(nèi)存模型的應(yīng)用

Java中的幾個關(guān)鍵字:volatile、final、synchronized,可以幫助程序員把代碼中的并發(fā)需求描述給編譯器。Java內(nèi)存模型中定義了它們的行為,以確保正確同步的Java代碼在所有的處理器架構(gòu)上都能正確執(zhí)行。

volatile

Java中,volatile關(guān)鍵字可以解決上面的問題,Java屏蔽掉這些差異,通過JVM生成內(nèi)存屏障的指令。

當(dāng)我們聲明某個變量為volatile修飾時,這個變量就有了線程可見性,volatile會在讀寫操作前后添加內(nèi)存屏障。volatile字段的每次讀行為都能看到其它線程最后一次對該字段的寫行為,通過它就可以避免拿到緩存中陳舊數(shù)據(jù)。它們必須保證在被寫入之后,會被刷新到主內(nèi)存中,這樣就可以立即對其它線程可以見。

final

如果一個類包含final字段,且在構(gòu)造函數(shù)中初始化,那么正確的構(gòu)造一個對象后,final字段被設(shè)置后對于其它線程是可見的。

注意這里所說的正確構(gòu)造對象,意思是在對象的構(gòu)造過程中,不允許對該對象進(jìn)行引用,不然的話,可能存在其它線程在對象還沒構(gòu)造完成時就對該對象進(jìn)行訪問,造成其他的問題。

synchronized

對于一個被synchronized修飾的monitor對象,只能夠被一個線程持有,意味著一旦有線程進(jìn)入了同步代碼塊,那么其它線程就不能進(jìn)入,直到第一個進(jìn)入的線程退出代碼塊。

在一個線程退出同步塊時,線程釋放monitor對象,它的作用是把CPU緩存數(shù)據(jù)(本地緩存數(shù)據(jù))刷新到主內(nèi)存中,從而實現(xiàn)該線程的行為可以被其它線程看到。在其它線程進(jìn)入到該代碼塊時,需要獲得monitor對象,它在作用是使CPU緩存失效,從而使變量從主內(nèi)存中重新加載,然后就可以看到之前線程對該變量的修改。

但從緩存的角度看,這個問題只會影響多處理器的機(jī)器,對于單核來說沒什么問題,但是它還有一個語義是禁止指令的重排序,對于編譯器來說,同步塊中的代碼不會移動到獲取和釋放monitor的外面。

總結(jié)

JMMJVM的一種規(guī)范,定義了JVM的內(nèi)存模型。它的主要目的是解決由于多線程通過共享內(nèi)存進(jìn)行通信時,存在的本地內(nèi)存數(shù)據(jù)不一致、編譯器會對代碼指令重排序、處理器會對代碼亂序執(zhí)行等帶來的問題。可以保證并發(fā)編程場景中的原子性、可見性和有序性。

Java中,volatilefinal、synchronized這三個關(guān)鍵字是對與內(nèi)存模型的具體實現(xiàn)。

“Java的內(nèi)存模型的應(yīng)用”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI