溫馨提示×

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

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

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

發(fā)布時(shí)間:2021-07-01 15:00:56 來(lái)源:億速云 閱讀:146 作者:Leah 欄目:大數(shù)據(jù)

Java中內(nèi)存模型的原理是什么,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。

1. JMM簡(jiǎn)要知識(shí)

語(yǔ)義規(guī)范

  • Java編程語(yǔ)言的語(yǔ)義允許編譯器和微處理器執(zhí)行優(yōu)化,從而與不正確同步的代碼進(jìn)行交互來(lái)完成工作.

  • 線(xiàn)程內(nèi)語(yǔ)義是單線(xiàn)程程序的語(yǔ)義,它允許根據(jù)線(xiàn)程內(nèi)讀操作看到的值來(lái)完全預(yù)測(cè)線(xiàn)程的行為;由于單線(xiàn)程內(nèi)的實(shí)現(xiàn)是在其上下文執(zhí)行的, 可以通過(guò)評(píng)估線(xiàn)程的實(shí)現(xiàn)從而確定執(zhí)行中的線(xiàn)程的操作是否合法.

  • 程序遵循線(xiàn)程內(nèi)語(yǔ)義: 在線(xiàn)程隔離狀態(tài)下,每個(gè)線(xiàn)程的操作必須由該線(xiàn)程的語(yǔ)義控制,但是每個(gè)讀操作看到的值由內(nèi)存模型決定.

JMM規(guī)范

  • 從數(shù)據(jù)存儲(chǔ)上,對(duì)于共享數(shù)據(jù)的讀寫(xiě)操作,JMM會(huì)通過(guò)線(xiàn)程工作內(nèi)存以及JVM的堆內(nèi)存來(lái)對(duì)數(shù)據(jù)進(jìn)行讀寫(xiě)操作(類(lèi)比互聯(lián)網(wǎng)業(yè)務(wù),工作內(nèi)存類(lèi)比為redis等緩存,堆內(nèi)存類(lèi)比為數(shù)據(jù)儲(chǔ)存載體,如數(shù)據(jù)庫(kù))

  • 從代碼優(yōu)化上,JMM為了提升性能,會(huì)針對(duì)程序順序代碼進(jìn)行重排序甚至刪除不必要的同步代碼

JMM概要

  • 給定程序以及一個(gè)檢測(cè)程序是否合法的執(zhí)行跟蹤,JMM工作原理是檢查執(zhí)行跟蹤中的每個(gè)讀,并根據(jù)某些規(guī)則檢查讀觀(guān)察到的寫(xiě)是否有效

  • 主要保證執(zhí)行的每個(gè)結(jié)果與內(nèi)存模型預(yù)期值一致,那么它可以不關(guān)心實(shí)現(xiàn)者是如何實(shí)現(xiàn)程序的行為

  • 內(nèi)存模型決定在程序的每個(gè)點(diǎn)可以讀取哪些值。在隔離狀態(tài)下,每個(gè)線(xiàn)程的操作必須由該線(xiàn)程的語(yǔ)義控制,但是每個(gè)讀操作看到的值由內(nèi)存模型決定

  • 每次在線(xiàn)程內(nèi)對(duì)變量進(jìn)行寫(xiě)行為產(chǎn)生一個(gè)線(xiàn)程間的動(dòng)作時(shí),它必須匹配程序順序中緊隨其后的讀行為的線(xiàn)程間動(dòng)作,其中對(duì)于線(xiàn)程的讀操作行為獲取的值是由于JMM決定的值

2. JMM與順序一致性模型

程序順序與順序一致性

  • 程序順序

    • 可描述為線(xiàn)程間所有動(dòng)作是根據(jù)線(xiàn)程內(nèi)語(yǔ)義執(zhí)行操作順序的一個(gè)集合

    • 簡(jiǎn)言之,就是在線(xiàn)程內(nèi)的操作所見(jiàn)即所得,即程序代碼順序

  • 順序一致性?xún)?nèi)存模型

    • 一個(gè)線(xiàn)程所有操作都必須按照程序的順序來(lái)執(zhí)行

    • 不論線(xiàn)程是否同步,所有線(xiàn)程都只能看到一個(gè)單一的操作執(zhí)行順序,并且每個(gè)操作都必須是原子性操作并立即對(duì)其他所有線(xiàn)程可見(jiàn)

  • 順序一致性問(wèn)題

    • 如果內(nèi)存模型使用一致性模型,則將會(huì)導(dǎo)致編譯器和處理器的優(yōu)化策略變得不合法

JMM在順序一致性方面的努力

  • 源代碼

// shared.java
int pwrite = 0;
int cwrite = 0;
// producer.java
int pread = 0;
int r1 = 0;
run(){
   r1 = 20; // --- 1
pread = cwrite; // --- 2
pwrite = 10; // --- 3
}
// consumer.java
int cread = 0;
int r2 = 0;
run(){
cread = pwrite; // --- 4
r2 = 21; // --- 5
cwrite = 20; // --- 6
}
  • 代碼分析

    • 基于JMM模型: 由于存在數(shù)據(jù)競(jìng)爭(zhēng),上面的代碼執(zhí)行順序會(huì)在編譯器階段,JMM允許對(duì)程序代碼進(jìn)行重排序,輸出結(jié)果會(huì)出現(xiàn)pread = cwrite = 20 與 cread = pwrite = 10的情況

    • 基于一致性?xún)?nèi)存模型: 將會(huì)正常輸出,不會(huì)出現(xiàn)pread = cwrite = 20 與 cread = pwrite = 10的情況,但是線(xiàn)程之間的順序會(huì)交替執(zhí)行

  • 加鎖方案

    • 基于JMM模型: 保證輸出結(jié)果的正常,但是在上述線(xiàn)程內(nèi)執(zhí)行的順序會(huì)被重排序

    • 一致性?xún)?nèi)存模型: 不會(huì)打亂順序,仍然正常結(jié)果輸出

  • 小結(jié)

    • 在存在數(shù)據(jù)競(jìng)爭(zhēng)的條件下,JMM無(wú)法保證線(xiàn)程之間的執(zhí)行順序,而順序一致性保證與代碼執(zhí)行的順序相同,即使線(xiàn)程的執(zhí)行順序存在交替執(zhí)行也不影響單個(gè)線(xiàn)程內(nèi)的執(zhí)行順序

    • 單個(gè)線(xiàn)程中,JMM仍然會(huì)對(duì)臨界區(qū)的執(zhí)行動(dòng)作進(jìn)行重排序,而順序一致性并沒(méi)有進(jìn)行重排,仍然保持與程序代碼相同的順序

3. JMM規(guī)范梳理

共享數(shù)據(jù)規(guī)則

  • 能夠被多個(gè)線(xiàn)程共享的內(nèi)存區(qū)域稱(chēng)為共享內(nèi)存或是堆內(nèi)存

  • 線(xiàn)程共享數(shù)據(jù): 所有的對(duì)象實(shí)例字段,static字段,數(shù)組元素等

  • 線(xiàn)程封閉數(shù)據(jù): 局部變量,方法參數(shù),異常處理器以及ThreadLocal/ThreadLocalRandom等

線(xiàn)程操作規(guī)則

相當(dāng)于線(xiàn)程行為可以被其他線(xiàn)程看到,也可以檢測(cè)到其他線(xiàn)程的行為動(dòng)作,程序行為表現(xiàn)如下:

  • 可以執(zhí)行正常的讀操作

  • 可以執(zhí)行正常的寫(xiě)操作

  • 對(duì)于同步代碼塊

    • 可以執(zhí)行volatile數(shù)據(jù)的讀取,說(shuō)明其他線(xiàn)程的寫(xiě)操作當(dāng)前線(xiàn)程可以“看到”(寫(xiě)操作在線(xiàn)程失效直接讀取主內(nèi)存)

    • 可以執(zhí)行volatile數(shù)據(jù)的寫(xiě),說(shuō)明變量數(shù)據(jù)可以對(duì)其他線(xiàn)程“可見(jiàn)”

    • lock鎖定監(jiān)視器

    • unlock解鎖監(jiān)視器

  • 線(xiàn)程合并執(zhí)行的第一個(gè)和最后一個(gè)動(dòng)作(個(gè)人理解為等待多個(gè)線(xiàn)程執(zhí)行子任務(wù)之后再一同執(zhí)行程序后續(xù)代碼的場(chǎng)景)

  • 啟動(dòng)線(xiàn)程和終止線(xiàn)程

Synchronization原則(能夠被感知,可見(jiàn)行為的變化)

  • 監(jiān)視器m的解鎖與監(jiān)視器m的后續(xù)動(dòng)作加鎖操作同步

  • 線(xiàn)程對(duì)volatile變量v進(jìn)行寫(xiě)操作,與任何線(xiàn)程對(duì)v的所有后續(xù)讀操作同步

  • 啟動(dòng)線(xiàn)程的操作與線(xiàn)程執(zhí)行的第一個(gè)動(dòng)作的操作同步

  • 在線(xiàn)程中對(duì)每個(gè)屬性執(zhí)行默認(rèn)值的寫(xiě)入操作與線(xiàn)程的第一個(gè)動(dòng)作操作同步

  • 線(xiàn)程中的最終動(dòng)作T1 與另一個(gè)線(xiàn)程T2中檢測(cè)到T1已終止的任何動(dòng)作同步

  • 如果線(xiàn)程T1中斷thread T2,則該中斷線(xiàn)程T1 將與 任何其他線(xiàn)程(包括T2)確定T2已被中斷(通過(guò)InterruptedException引發(fā)或調(diào)用Thread.interrupted 或Thread.isInterrupted)的任何點(diǎn)同步

Happen-Before原則(規(guī)范)

  • 執(zhí)行動(dòng)作之間的happen-before關(guān)系 

    如果兩個(gè)動(dòng)作x和y,我們定義hb(x,y)來(lái)描述x happen before y,滿(mǎn)足關(guān)系有以下情況:

    • 同一個(gè)線(xiàn)程中執(zhí)行動(dòng)作x和y,在程序順序上x(chóng)優(yōu)先于y,則hb(x,y)

    • 對(duì)象構(gòu)造器代碼塊的結(jié)束happen-before該對(duì)象finalizer的開(kāi)始

    • 如果x動(dòng)作與接下來(lái)的y動(dòng)作同步,則hb(x,y)

    • 傳遞性,如果hb(x,y),且hb(y,z),則hb(x,z)

  • happen-before原則 

    主要作用于兩個(gè)的動(dòng)作存在沖突的執(zhí)行順序以及定義數(shù)據(jù)競(jìng)爭(zhēng)發(fā)生的時(shí)機(jī),具體VM實(shí)現(xiàn),遵循以下原則:

    • 線(xiàn)程解鎖動(dòng)作都happen-before該線(xiàn)程的后續(xù)動(dòng)作鎖操作

    • 對(duì)volatile變量執(zhí)行寫(xiě)操作happen-before該變量讀操作的后續(xù)每個(gè)動(dòng)作

    • 調(diào)用線(xiàn)程的start()方法happen-before于已開(kāi)啟的線(xiàn)程內(nèi)的任何一個(gè)動(dòng)作

    • 線(xiàn)程所有動(dòng)作happen-before于其他任意線(xiàn)程成功從該線(xiàn)程對(duì)象的join()方法返回

    • 程序任何對(duì)象的初始化happen-before于程序中任何其他的動(dòng)作操作行為

  • 作用

    • 遵循上述的原則,意味著有些代碼不能進(jìn)行重排序,有些數(shù)據(jù)不能被緩存(解決JMM可見(jiàn)性的規(guī)范)

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

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

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guā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