java內(nèi)存模型知識(shí)點(diǎn)整理

一.內(nèi)存間交互操作
本身是一種抽象概念,描述了一組規(guī)則或規(guī)范,定義了程序各個(gè)變量的訪問(wèn)規(guī)則,java線程模型規(guī)定了所有變量都存儲(chǔ)在主內(nèi)存種,每條線程還有自己的工作內(nèi)存。線程的工作內(nèi)存保留了被該線程使用到的變量的主內(nèi)存副本拷貝。線程對(duì)變量的所有操作必須在工作內(nèi)存中進(jìn)行,不能直接讀寫主內(nèi)存中的變量。不同線程之間也訪問(wèn)對(duì)方的工作內(nèi)存。線程間變量的值傳遞需要通過(guò)主內(nèi)存來(lái)完成.
java內(nèi)存模型定義了如下八種操作來(lái)完成主內(nèi)存與工作內(nèi)存之間的交互,每一種操作都是原子的不可分割的:

  1. lock(鎖定):作用于主內(nèi)存變量,將一個(gè)變量標(biāo)識(shí)為線程獨(dú)占狀態(tài)。
  2. unlock(解鎖)
  3. read(讀?。鹤饔糜谥鲀?nèi)存變量,把一個(gè)變量從主內(nèi)存?zhèn)鬏數(shù)骄€程的工作內(nèi)存中。
  4. load(載入):作用于工作內(nèi)存變量,把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中。
  5. use(使用):作用于工作內(nèi)存的變量,把工作內(nèi)存的變量傳遞給執(zhí)行引擎。
  6. assign(賦值):作用于工作內(nèi)存變量,它把一個(gè)從執(zhí)行引擎接收到的值賦給工作內(nèi)存變量,當(dāng)虛擬機(jī)接收到給一個(gè)變量賦值的字節(jié)碼指令時(shí)會(huì)執(zhí)行這個(gè)操作。
  7. store(存儲(chǔ)):作用于工作內(nèi)存變量,把工作內(nèi)存中一個(gè)變量的值傳送到主內(nèi)存中。
  8. write(寫入):作用于主內(nèi)存變量,它把store操作從工作內(nèi)存中得到的變量的值放入主內(nèi)存變量中。

執(zhí)行上述八中操作必須滿足如下規(guī)則:

  1. 不允許read load、store write操作之一單獨(dú)出現(xiàn)。
  2. 不允許一個(gè)線程丟棄他最近的assign操作。即變量再工作內(nèi)存中改變了后必須同步回主內(nèi)存。
  3. 不允許一個(gè)線程無(wú)原因的(沒(méi)有發(fā)生過(guò)任何assign操作)把數(shù)據(jù)從線程的工作內(nèi)存同步到主內(nèi)存中。
  4. 一個(gè)新的變量只能在主內(nèi)存中誕生,不允許在工作內(nèi)存中直接使用一個(gè)未被初始化的(load或assign)變量。也就是說(shuō)對(duì)一個(gè)變量load或store之前,必須read或assign。
  5. 一個(gè)變量在同一時(shí)刻只允許一條線程對(duì)其進(jìn)行l(wèi)ock操作,但lock操作可以被同一條線程多次執(zhí)行,多次執(zhí)行l(wèi)ock后,只有相同次數(shù)的unlock操作,變量才會(huì)被解鎖。
  6. 對(duì)一個(gè)變量執(zhí)行l(wèi)ock操作,會(huì)清空工作內(nèi)存中此變量的值,在執(zhí)行引擎使用這個(gè)變量前,需要重新使用load或assign操作初始化變量的值。
  7. 沒(méi)有被lock 不許unlock。
  8. 對(duì)一個(gè)變量unlock前,必須把此變量同步回主存中。

二.volatile變量的特殊規(guī)則
volatile可以看作一種“程度較輕的Synchronized”,但相較于synchronized提供的“原子性”和“可見(jiàn)性”,volatile變量只擁有可見(jiàn)性。volatile變量的兩種特性如下:
1.保證此變量對(duì)所有線程的可見(jiàn)性,這里的可見(jiàn)性是指當(dāng)一條線程修改了這個(gè)變量的值,新值對(duì)其他線程可以是立即得知的。
但volatile變量在并發(fā)環(huán)境下的運(yùn)算并不是線程安全的,因?yàn)樗⒉痪邆湓有裕栽诓环先缦聝蓚€(gè)規(guī)則的運(yùn)算中,仍需要加鎖保證原子性:
1)運(yùn)算結(jié)果并不依賴當(dāng)前變量的值,或者能夠確保只有單一的線程修改變量的值
2)變量不需要與其他狀態(tài)的變量共同參與不變約束。
2.禁止指令重排序
普通變量只能保證在該方法的執(zhí)行過(guò)程中所依賴賦值結(jié)果的地方都能獲得正確的結(jié)果,而不能保證變量賦值的操作順序與程序代碼的中的執(zhí)行順序一致。
但是在單個(gè)線程中指令重排序并不會(huì)影響程序的執(zhí)行結(jié)果,但在并發(fā)環(huán)境下,會(huì)存在問(wèn)題,volatile會(huì)禁止指令重排序??康氖莾?nèi)存屏障。有volatile修飾的變量,賦值后會(huì)多執(zhí)行了一個(gè)“l(fā)ock add1 0x0,(esp)”的操作,這個(gè)操作相當(dāng)于一個(gè)內(nèi)存屏障,lock前綴使得本cpu的cache寫入主存,也會(huì)使別的cpu或內(nèi)核無(wú)效化其cache,相當(dāng)于對(duì)cache中變量做了一次store和write操作。 lock add10x0,(esp)把修改同步到內(nèi)存時(shí),意味著之前所有的操作都已經(jīng)完成了。
T表示一個(gè)線程,V,W表示兩個(gè)volatile型變量。

  1. 只有線程T對(duì)V執(zhí)行前一個(gè)動(dòng)作是load時(shí),T才能對(duì)V執(zhí)行use動(dòng)作。當(dāng)T對(duì)V的后一個(gè)動(dòng)作時(shí)use時(shí),才能執(zhí)行l(wèi)oad動(dòng)作,T對(duì)V的use動(dòng)作與load read動(dòng)作相關(guān)聯(lián),必須連續(xù)一起出現(xiàn)(每次使用V之前,必須從其他主存刷新最新值,保證能看到其他線程對(duì)V變量修改后的值。)
  2. 與1相同,assign操作與store,write動(dòng)作相關(guān)聯(lián),必須一起出現(xiàn)(在工作內(nèi)存中,每次修改V后,都必須立刻同步回主存中)
  3. 假定動(dòng)作A是線程T對(duì)變量V實(shí)施的use或assign操作,假定動(dòng)作F是和動(dòng)作A相關(guān)聯(lián)的load或store操作,假定動(dòng)作P是動(dòng)作F相對(duì)應(yīng)的對(duì)變量V的read或write動(dòng)作。假定動(dòng)作B是線程T對(duì)變量W實(shí)施的use或assign操作,假定動(dòng)作G是和動(dòng)作A相關(guān)聯(lián)的load或store操作,假定動(dòng)作Q是動(dòng)作F相對(duì)應(yīng)的對(duì)變量V的read或write動(dòng)作。如果A先于B,那么P先于Q。(這條指令要求volatile修飾的變量不會(huì)被指令排序優(yōu)化,保證代碼執(zhí)行順序與程序相同)。
    volatile變量讀性能消耗與普通變量差不多,但是寫操作可能滿一下,因?yàn)樗枰诒镜卮a中插入許多內(nèi)存屏障指令來(lái)保證處理器不發(fā)生亂序執(zhí)行。

三.Java內(nèi)存模型的特征:
原子性、可見(jiàn)性、有序性
1.原子性:Java內(nèi)存模型保證的原子性操作包括:read load use assign store write?;緮?shù)據(jù)類型的讀寫是原子性的。Synchronized塊之間的操作也具備原子性。
2.可見(jiàn)性:指的是一個(gè)線程修改了共享變量的值,其他線程立即得知。Java內(nèi)存模型是通過(guò)在變量修改后將新值同步回主內(nèi)存,在變量讀取前從主內(nèi)存刷新變量值這種依賴主內(nèi)存未傳遞媒介的方式實(shí)現(xiàn)可見(jiàn)性。除了volatile,synchronized和final也可實(shí)現(xiàn)可見(jiàn)性。
同步塊的可見(jiàn)性是由“對(duì)一個(gè)變量執(zhí)行unlock操作之前,必須先把此變量同步回主存中(store,write)”實(shí)現(xiàn)的。Final可見(jiàn)性是指一旦final字段在構(gòu)造器中初始化完成,其他線程中就能看到final字段的值。
3.有序性:如果在本線程內(nèi)觀察,所有操作都是有序的,如果在一個(gè)線程內(nèi)觀察另一個(gè)線程,所有操作都是無(wú)序的。前半句表示線程內(nèi)表示為串行的語(yǔ)義,后半句是指“指令重排序”現(xiàn)象和“工作內(nèi)存與主內(nèi)存同步延遲現(xiàn)象”。
Volatile和synchronized關(guān)鍵字保證線程之間操作的有序性,volatile關(guān)鍵字本身就包括了禁止指令重排序的語(yǔ)義,synchronized是由“一個(gè)變量同一時(shí)刻只允許一個(gè)線程對(duì)其lock操作”獲得的。

先行發(fā)生原則(happen-before):如果操作A先行發(fā)生于操作B,那么在操作B之前,操作A產(chǎn)生的影響能被操作B觀察到。“影響”包括修改了共享變量的值,發(fā)送了信息,調(diào)用了方法等。
Java內(nèi)存模型下一些天然的先行發(fā)生關(guān)系:
1.程序次序規(guī)則:
2.管程鎖定規(guī)則:
3.volatile變量規(guī)則:
4.線程啟動(dòng)規(guī)則
5.線程終止規(guī)則
6.線程中斷規(guī)則
7.對(duì)象終結(jié)規(guī)則
8.傳遞性
一個(gè)操作時(shí)間上先發(fā)生不代表先行發(fā)生,同時(shí)先行發(fā)生也不代表時(shí)間上先發(fā)生。(指令重排序)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容