您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Java內(nèi)存模型的知識(shí)點(diǎn)講解”的有關(guān)知識(shí),在實(shí)際案例的操作過(guò)程中,不少人都會(huì)遇到這樣的困境,接下來(lái)就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
內(nèi)存模型 (memory model)
內(nèi)存模型描述的是程序中各變量(實(shí)例域、靜態(tài)域和數(shù)組元素)之間的關(guān)系,以及在實(shí)際計(jì)算機(jī)系統(tǒng)中將變量存儲(chǔ)到內(nèi)存和從內(nèi)存取出變量這樣的低層細(xì)節(jié).
不同平臺(tái)間的處理器架構(gòu)將直接影響內(nèi)存模型的結(jié)構(gòu).
在C或C++中, 可以利用不同操作平臺(tái)下的內(nèi)存模型來(lái)編寫并發(fā)程序. 但是, 這帶給開發(fā)人員的是, 更高的學(xué)習(xí)成本.相比之下, Java利用了自身虛擬機(jī)的優(yōu)勢(shì), 使內(nèi)存模型不束縛于具體的處理器架構(gòu), 通過(guò)Java內(nèi)存模型真正實(shí)現(xiàn)了跨平臺(tái).(針對(duì)hotspot jvm, jrockit等不同的jvm, 內(nèi)存模型也會(huì)不相同)
內(nèi)存模型的特征:
a, Visibility 可視性 (多核,多線程間數(shù)據(jù)的共享)
b, Ordering 有序性 (對(duì)內(nèi)存進(jìn)行的操作應(yīng)該是有序的)
Java內(nèi)存模型 ( java memory model )
根據(jù)Java Language Specification中的說(shuō)明, jvm系統(tǒng)中存在一個(gè)主內(nèi)存(Main Memory或Java Heap Memory),Java中所有變量都儲(chǔ)存在主存中,對(duì)于所有線程都是共享的。
每條線程都有自己的工作內(nèi)存(Working Memory),工作內(nèi)存中保存的是主存中某些變量的拷貝,線程對(duì)所有變量的操作都是在工作內(nèi)存中進(jìn)行,線程之間無(wú)法相互直接訪問(wèn),變量傳遞均需要通過(guò)主存完成。
其中, 工作內(nèi)存里的變量, 在多核處理器下, 將大部分儲(chǔ)存于處理器高速緩存中, 高速緩存在不經(jīng)過(guò)內(nèi)存時(shí), 也是不可見的.
jmm怎么體現(xiàn)可視性(Visibility) ?
在jmm中, 通過(guò)并發(fā)線程修改變量值, 必須將線程變量同步回主存后, 其他線程才能訪問(wèn)到.
jmm怎么體現(xiàn)有序性(Ordering) ?
通過(guò)Java提供的同步機(jī)制或volatile關(guān)鍵字, 來(lái)保證內(nèi)存的訪問(wèn)順序.
緩存一致性(cache coherency)
什么是緩存一致性?
它是一種管理多處理器系統(tǒng)的高速緩存區(qū)結(jié)構(gòu),其可以保證數(shù)據(jù)在高速緩存區(qū)到內(nèi)存的傳輸中不會(huì)丟失或重復(fù)。(來(lái)自wikipedia)
舉例理解:
假如有一個(gè)處理器有一個(gè)更新了的變量值位于其緩存中,但還沒(méi)有被寫入主內(nèi)存,這樣別的處理器就可能會(huì)看不到這個(gè)更新的值.
解決緩存一致性的方法?
a, 順序一致性模型:
要求某處理器對(duì)所改變的變量值立即進(jìn)行傳播, 并確保該值被所有處理器接受后, 才能繼續(xù)執(zhí)行其他指令.
b, 釋放一致性模型: (類似jmm cache coherency)
允許處理器將改變的變量值延遲到釋放鎖時(shí)才進(jìn)行傳播.
Java內(nèi)存模型的緩存一致性模型 - "happens-before ordering(先行發(fā)生排序)"
一般情況下的示例程序:
x = 0; y = 0; i = 0; j = 0; // thread A y = 1; x = 1; // thread B i = x; j = y;
在如上程序中, 如果線程A,B在無(wú)保障情況下運(yùn)行, 那么i,j各會(huì)是什么值呢?
答案是, 不確定. (00,01,10,11都有可能出現(xiàn)),這里沒(méi)有使用Java同步機(jī)制, 所以Java內(nèi)存模型有序性和可視性都無(wú)法得到保障. happens-before ordering( 先行發(fā)生排序) 如何避免這種情況? 排序原則已經(jīng)做到:
a, 在程序順序中, 線程中的每一個(gè)操作, 發(fā)生在當(dāng)前操作后面將要出現(xiàn)的每一個(gè)操作之前.
b, 對(duì)象監(jiān)視器的解鎖發(fā)生在等待獲取對(duì)象鎖的線程之前.
c, 對(duì)volitile關(guān)鍵字修飾的變量寫入操作, 發(fā)生在對(duì)該變量的讀取之前.
d, 對(duì)一個(gè)線程的 Thread.start() 調(diào)用 發(fā)生在啟動(dòng)的線程中的所有操作之前.
e, 線程中的所有操作 發(fā)生在從這個(gè)線程的 Thread.join()成功返回的所有其他線程之前.
為了實(shí)現(xiàn) happends-before ordering原則, Java及JDK提供的工具:
a, synchronized關(guān)鍵字
b, volatile關(guān)鍵字
c, final變量
d, java.util.concurrent.locks包(since jdk 1.5)
e, java.util.concurrent.atmoic包(since jdk 1.5)
使用了happens-before ordering的例子:
1) 獲取對(duì)象監(jiān)視器的鎖(lock)
(2) 清空工作內(nèi)存數(shù)據(jù), 從主存復(fù)制變量到當(dāng)前工作內(nèi)存, 即同步數(shù)據(jù) (read and load)
(3) 執(zhí)行代碼,改變共享變量值 (use and assign)
(4) 將工作內(nèi)存數(shù)據(jù)刷回主存 (store and write)
(5) 釋放對(duì)象監(jiān)視器的鎖 (unlock)
注意: 其中4,5兩步是同時(shí)進(jìn)行的.
這邊最核心的就是第二步, 他同步了主內(nèi)存,即前一個(gè)線程對(duì)變量改動(dòng)的結(jié)果,可以被當(dāng)前線程獲知!(利用了happens-before ordering原則)
對(duì)比之前的例子
如果多個(gè)線程同時(shí)執(zhí)行一段未經(jīng)鎖保護(hù)的代碼段,很有可能某條線程已經(jīng)改動(dòng)了變量的值,但是其他線程卻無(wú)法看到這個(gè)改動(dòng),依然在舊的變量值上進(jìn)行運(yùn)算,最終導(dǎo)致不可預(yù)料的運(yùn)算結(jié)果。
“Java內(nèi)存模型的知識(shí)點(diǎn)講解”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(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)容。