溫馨提示×

溫馨提示×

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

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

Java內(nèi)存模型的原理是什么

發(fā)布時(shí)間:2021-07-01 17:27:28 來源:億速云 閱讀:190 作者:Leah 欄目:編程語言

這篇文章將為大家詳細(xì)講解有關(guān)Java內(nèi)存模型的原理是什么,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對相關(guān)知識(shí)有一定的了解。

所有的編程語言中都有內(nèi)存模型這個(gè)概念,區(qū)別于微架構(gòu)的內(nèi)存模型,高級(jí)語言的內(nèi)存模型包括了編譯器和微架構(gòu)兩部分。我試圖了解了Java、C#和Go語言的內(nèi)存模型,發(fā)現(xiàn)內(nèi)容基本大同小異,只是這些語言在具體實(shí)現(xiàn)的時(shí)候略有不同。

我們來看看Java內(nèi)存模型吧,提到Java內(nèi)存模型大家對這個(gè)圖一定非常熟悉:

Java內(nèi)存模型的原理是什么

這張圖告訴我們在線程運(yùn)行的時(shí)候有一個(gè)內(nèi)存專用的一小塊內(nèi)存,當(dāng)Java程序會(huì)將變量同步到線程所在的內(nèi)存,這時(shí)候會(huì)操作工作內(nèi)存中的變量,而線程 中變量的值何時(shí)同步回主內(nèi)存是不可預(yù)期的。但同時(shí)Java內(nèi)存模型又告訴我們通過使用關(guān)鍵詞“synchronized”或“volatile”可以讓 Java保證某些約束:

“volatile” — 保證讀寫的都是主內(nèi)存的變量

“synchronized” — 保證在塊開始時(shí)都同步主內(nèi)存的值到工作內(nèi)存,而塊結(jié)束時(shí)將變量同步回主內(nèi)存

通過以上描述我們就可以寫出線程安全的Java程序,JDK也同時(shí)幫我們屏蔽了很多底層的東西。

但當(dāng)你深入了解JVM的時(shí)候你會(huì)發(fā)現(xiàn)根本就沒有工作內(nèi)存這個(gè)東西,即內(nèi)存中根本不會(huì)分配這么一塊空間來運(yùn)行你的Java程序,那么工作內(nèi)存到底是什么東西呢?

這個(gè)問題也曾經(jīng)困擾了我很長時(shí)間,因?yàn)槲覐膩頉]有從JVM的實(shí)現(xiàn)中找到過和主內(nèi)存同步的代碼,因?yàn)楫?dāng)使用“volatile”時(shí)我僅僅能從源代碼中調(diào)用了這行語句:

__asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");

而這個(gè)指令在部分微架構(gòu)上的主要功能就是防止指令重排,即這條指令前后的其它指令不會(huì)越過這個(gè)界限執(zhí)行[注1]。

在現(xiàn)在的x86/x64微架構(gòu)中讀寫內(nèi)存的一致性都是通過MESI(Intel使用MESI-F,AMD使用MOESI)協(xié)議保證[注2],MESI的狀態(tài)轉(zhuǎn)換圖如下:

Java內(nèi)存模型的原理是什么

更詳細(xì)的中文文檔描述可以查看這個(gè)文檔:http://blog.csdn.net/zhuliting/article/details/6210921

那Java內(nèi)存模型中所說的工作內(nèi)存是什么呢?

我的理解是,首先“工作內(nèi)存”是一個(gè)虛擬的概念,而承載這個(gè)概念主要是兩部分:

1. 編譯器

2. 微架構(gòu)

作為編譯器肯定是執(zhí)行速度越快越好,所以作為編譯器應(yīng)當(dāng)盡量減少從內(nèi)存讀數(shù)據(jù),如果一個(gè)數(shù)據(jù)在寄存器中,那么直接使用寄存器中的值無疑性能是*** 的,但同時(shí)這也會(huì)導(dǎo)致可能讀不到***的值,這里我們通過在Java語言中為變量加上“volatile”強(qiáng)制告訴編譯器這個(gè)變量一定要從內(nèi)存獲得,這時(shí)編 譯器即不會(huì)做此類優(yōu)化【案例見參考資料5(是一個(gè).Net的例子)】。

對于微架構(gòu)來說,在x86/x64下,CPU會(huì)在執(zhí)行指令時(shí)做指令重排,即編譯器生成的指令順序和真正在CPU執(zhí)行的順序可能是不一致的。當(dāng)我們用一個(gè)變量做信號(hào)的時(shí)候這種指令重排會(huì)帶來悲劇,即如果有如下代碼:

x = 0; y = 0; i = 0; j = 0; // thread A y = 1; x = 1; // thread B i = x; j = y;

上面的代碼i和j的值會(huì)是多少呢?答案是:“00, 01, 10, 11”都是有可能的。

對于這種情況,如果我們想得到確定的結(jié)果則需要通過“synchronized”(或者j.c.u.locks)來做線程間同步。

所以,我個(gè)人對Java內(nèi)存模型的理解是:在編譯器各種優(yōu)化及多種類型的微架構(gòu)平臺(tái)上,Java語言規(guī)范制定者試圖創(chuàng)建一個(gè)虛擬的概念并傳遞到 Java程序員,讓他們能夠在這個(gè)虛擬的概念上寫出線程安全的程序來,而編譯器實(shí)現(xiàn)者會(huì)根據(jù)Java語言規(guī)范中的各種約束在不同的平臺(tái)上達(dá)到Java程序 員所需要的線程安全這個(gè)目的。

關(guān)于Java內(nèi)存模型的原理是什么就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。

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

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

AI