溫馨提示×

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

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

Java并發(fā)編程中的內(nèi)存模型是什么

發(fā)布時(shí)間:2021-11-23 08:52:53 來(lái)源:億速云 閱讀:393 作者:iii 欄目:開(kāi)發(fā)技術(shù)

這篇文章主要介紹“Java并發(fā)編程中的內(nèi)存模型是什么”,在日常操作中,相信很多人在Java并發(fā)編程中的內(nèi)存模型是什么問(wèn)題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”Java并發(fā)編程中的內(nèi)存模型是什么”的疑惑有所幫助!接下來(lái),請(qǐng)跟著小編一起來(lái)學(xué)習(xí)吧!

    1、什么是Java的內(nèi)存模型

    Java內(nèi)存模型簡(jiǎn)稱JMM(Java Memory Model),JMM是和多線程并發(fā)相關(guān)的一組規(guī)范。各個(gè)jvm實(shí)現(xiàn)都要遵循這個(gè)JMM規(guī)范。才能保證Java代碼在不同虛擬機(jī)順利運(yùn)行。因此,JMM 與處理器、緩存、并發(fā)、編譯器有關(guān)。它解決了CPU 多級(jí)緩存、處理器優(yōu)化、指令重排等導(dǎo)致的結(jié)果不可預(yù)期的問(wèn)題。

    Java并發(fā)編程中的內(nèi)存模型是什么

    2、為什么需要Java內(nèi)存模型

    程序的運(yùn)行結(jié)果依賴于處理器,而不同的處理器規(guī)則都不一樣,不同處理器差異是很大的,所以同段代碼在處理器A運(yùn)行正常,搬到處理器B運(yùn)行結(jié)果是不一樣的,所以為了兼容這種差異,推出了Java內(nèi)存模型規(guī)范,JMM是一個(gè)規(guī)范標(biāo)準(zhǔn),JMM保證了不同處理器的處理結(jié)果一致,同時(shí)也保證不同編譯器、jvm等等的一致性。所以就保證了Java語(yǔ)言“書寫一次、到處運(yùn)行”

    3、Java內(nèi)存模型及操作規(guī)范

    1.共享變量都是放在主內(nèi)存中的

    2.每個(gè)線程都有自己的工作內(nèi)存,線程只可操作自己的工作內(nèi)存

    3.線程要操作共享變量,需要從主內(nèi)存中讀取到工作內(nèi)存,改變值之后要從工作內(nèi)存同步到主內(nèi)存

    Java并發(fā)編程中的內(nèi)存模型是什么

    4、Java內(nèi)存模型規(guī)定的原子操作

    Java內(nèi)存模型的同步交換協(xié)議,規(guī)定了8種原子操作

    原子操作:不可被中斷的一個(gè)或一系列操作

    • lock(鎖定):將主內(nèi)存中的變量鎖定,為一個(gè)線程所獨(dú)占

    • unlock(解鎖):將lock加的鎖解除,其他的線程有機(jī)會(huì)訪問(wèn)此變量

    • read(讀取):作用于主內(nèi)存變量,將主內(nèi)存中的變量值讀取到工作內(nèi)存

    • load(加載):作用于工作內(nèi)存,將read讀取到的值保存到工作內(nèi)存中的變量副本

    • use(使用):作用于工作內(nèi)存變量,將值傳遞給線程的代碼執(zhí)行引擎

    • assign(賦值):作用于工作內(nèi)存變量,將執(zhí)行引擎處理返回的值重新賦值給變量副本

    • store(存儲(chǔ)):作用于工作內(nèi)存變量,將變量副本的值傳送到主內(nèi)存中

    • write(寫入):作用于主內(nèi)存變量,將store傳送過(guò)來(lái)的值寫入到主內(nèi)存的共享變量中

    Java內(nèi)存模型的同步交互協(xié)議,執(zhí)行上述8種原子操作時(shí)必須滿足如下規(guī)則

    不允許read和load,store和write操作之一單獨(dú)出現(xiàn)。即不允許加載或同步工作到一半。

    不允許一個(gè)線程丟棄它最近的assign操作,即變量在工作內(nèi)存中改變之后,必須將數(shù)據(jù)同步回主內(nèi)存

    不允許一個(gè)線程無(wú)原因地(無(wú)assign操作)將數(shù)據(jù)從工作內(nèi)存同步到主內(nèi)存中。

    一個(gè)新的變量可能在主內(nèi)存中誕生。

    一個(gè)變量在同一個(gè)時(shí)刻只允許一條線程對(duì)其進(jìn)行l(wèi)ock操作,但lock操作可以被同一條線程重復(fù)執(zhí)行多次,多次lock之后必須要執(zhí)行相同次數(shù)unlock操作,變量才會(huì)解鎖

    如果對(duì)一個(gè)對(duì)象進(jìn)行l(wèi)ock操作,那么會(huì)清空工作內(nèi)存變量中的值,在執(zhí)行引擎使用這個(gè)變量前,需要重新執(zhí)行l(wèi)oad或assign操作初始變量的值

    如果一個(gè)對(duì)象事先沒(méi)有被lock,就不允許對(duì)其進(jìn)行unlock操作,也不允許去unlock一個(gè)被其他線程鎖住的變量。

    對(duì)一個(gè)變量執(zhí)行unlock操作之前,必須將此變量同步回主內(nèi)存中(執(zhí)行store、write)

    5、Java內(nèi)存模型同步協(xié)議

    Java內(nèi)存模型的同步協(xié)議,操作規(guī)范 將一個(gè)變量從主內(nèi)存復(fù)制到工作內(nèi)存要順序執(zhí)行read、load操作;要將變量從工作內(nèi)存同步回主內(nèi)存要用store、write操作。只要求順序執(zhí)行,不一定是連續(xù)執(zhí)行

    圖引用網(wǎng)上資料:

    Java并發(fā)編程中的內(nèi)存模型是什么

    6、Java內(nèi)存模型的HB法則

    并發(fā)編程有三個(gè)重要特效:原子行可見(jiàn)性、有序性

    • 原子性:原子性是指一個(gè)或者多個(gè)操作,要么全部執(zhí)行且執(zhí)行過(guò)程不會(huì)被其它操作打斷,要么全部不執(zhí)行。

    • 可見(jiàn)性:可見(jiàn)性是指共享變量對(duì)于多個(gè)線程都是可見(jiàn)的,也即一個(gè)線程修改了變量,其它線程馬上就能知道

    • 有序性:有序性是指程序的執(zhí)行順序按照代碼的先后順便執(zhí)行

    在說(shuō)JMM的happens-before(HB)法則之前,先說(shuō)說(shuō)并發(fā)編程的有序性。說(shuō)到并發(fā)線程的有序性,還需要涉及到指令重排序

    • 什么是指令重排?

    假如我們寫一個(gè)程序,我們會(huì)期待這些語(yǔ)句的實(shí)際執(zhí)行順便和代碼的順序是一致的,大部分情況是一致的,但實(shí)際上,編譯器、JVM 或者 CPU 都有可能出于優(yōu)化等目的,對(duì)執(zhí)行的順序進(jìn)行調(diào)整,這個(gè)就是指令重排序

    • 重排序的好處:提高處理速度

    代碼順序如圖:

    Java并發(fā)編程中的內(nèi)存模型是什么

    指令重排后,a=100; a= a+100會(huì)提到一起執(zhí)行,效率提高

    Java并發(fā)編程中的內(nèi)存模型是什么

    上面的例子,是可以提高執(zhí)行效率,但是有時(shí)候指令重排是會(huì)導(dǎo)致問(wèn)題的,如下代碼例子,代碼順序是先初始化content,然后設(shè)置標(biāo)識(shí)為true,線程B檢測(cè)到為true之后,調(diào)用content的方法

    Java并發(fā)編程中的內(nèi)存模型是什么

    如果指令重排后,這種情況就會(huì)出現(xiàn)沒(méi)初始化完成,就直接調(diào)用conten的方法

    Java并發(fā)編程中的內(nèi)存模型是什么

    所以,指令重排有好處也有壞處,一般可能是cpu、編譯器或者是內(nèi)存會(huì)進(jìn)行指令重排,為了避免指令重排,保證并發(fā)編程的有序性,有時(shí)候需要使用synchronized等鎖或者volatile等等方式避免

    1.JMM規(guī)定了happens-before(先行發(fā)生)原則,來(lái)保證很多操作的有序性。

    2.當(dāng)我們代碼操作不滿足先行發(fā)生原則時(shí),則需在編碼時(shí)使用volatile、synchronized來(lái)保證有序性

    JMM的HB法則

    • 程序順序規(guī)則:每個(gè)線程的每個(gè)操作都happens-before該線程中任意的后續(xù)操作

    • 監(jiān)視器鎖規(guī)則:一個(gè)鎖的解除,happens-before于隨后對(duì)這個(gè)鎖的加鎖

    • volatile變量規(guī)則:對(duì)volatile域的寫,happens-before于任意后續(xù)對(duì)這個(gè)volatile域的讀

    • 線程啟動(dòng)規(guī)則:在某個(gè)線程對(duì)象上調(diào)用start()方法happens-before被啟動(dòng)線程中的任意動(dòng)作

    • 線程終止規(guī)則:線程中所有操作都先行發(fā)生于對(duì)此線程的終止檢測(cè),如在線程t1中成功執(zhí)行了t2.join(),則t2中的所有操作對(duì)t2可見(jiàn)

    • 線程中斷規(guī)則:對(duì)線程interrupt()方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測(cè)到中斷事件的發(fā)生

    • 對(duì)象終結(jié)規(guī)則:一個(gè)對(duì)象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行發(fā)生于它的finalize方法的開(kāi)始傳

    • 遞性:如果A happens-before于B,且B happens-before 于C,那么A happens-before于C

    到此,關(guān)于“Java并發(fā)編程中的內(nèi)存模型是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)?lái)更多實(shí)用的文章!

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

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

    AI