處理器、高速緩存、主內(nèi)存間的交互關(guān)系
線(xiàn)程、主內(nèi)存、工作內(nèi)存三者的交互關(guān)系java內(nèi)存模型中定義了以下8中操作來(lái)完成主內(nèi)存與工作內(nèi)存之間交互的實(shí)現(xiàn)細(xì)節(jié):
1、luck(鎖定):作用于主內(nèi)存的變量,它把一個(gè)變量標(biāo)示為一條線(xiàn)程獨(dú)占的狀態(tài)。
2、unlock(解鎖):作用于主內(nèi)存的變量,它把一個(gè)處于鎖定狀態(tài)的變量釋放出來(lái),釋放后的變量才可以被其他線(xiàn)程鎖定。
3、read(讀取):作用于主內(nèi)存的變量,它把一個(gè)變量的值從主內(nèi)存?zhèn)鬏數(shù)焦ぷ鲀?nèi)存中,以便隨后的load動(dòng)作使用。
4、load(載入):作用于工作內(nèi)存的變量,它把read操作從主內(nèi)存中得到的變量值放入工作內(nèi)存的變量副本中。
5、use(使用):作用于工作內(nèi)存的變量,它把工作內(nèi)存中的一個(gè)變量的值傳遞給執(zhí)行引擎,每當(dāng)虛擬機(jī)遇到一個(gè)需要使用到變量的值得字節(jié)碼指令時(shí)將會(huì)執(zhí)行這個(gè)操作。
6、assign(賦值):作用于工作內(nèi)存的變量,它把一個(gè)從執(zhí)行引擎接收到的值賦給工作內(nèi)存的變量,每當(dāng)虛擬機(jī)遇到一個(gè)給變量賦值的字節(jié)碼指令時(shí)執(zhí)行這個(gè)操作。
7、store(存儲(chǔ)):作用于工作內(nèi)存的變量,它把工作內(nèi)存中的一個(gè)變量的值傳遞到主內(nèi)存中,以便隨后的write操作使用。
8、write(寫(xiě)入):作用于主內(nèi)存的變量,它把store操作從工作內(nèi)存中得到的變量值放入主內(nèi)存的變量中。
Java內(nèi)存模型還規(guī)定了執(zhí)行上述8種基本操作時(shí)必須滿(mǎn)足如下規(guī)則:
1、不允許read和load、store和write操作之一單獨(dú)出現(xiàn),以上兩個(gè)操作必須按順序執(zhí)行,但沒(méi)有保證必須連續(xù)執(zhí)行,也就是說(shuō),read與load之間、store與write之間是可插入其他指令的。
2、不允許一個(gè)線(xiàn)程丟棄它的最近的assign操作,即變量在工作內(nèi)存中改變了之后必須把該變化同步回主內(nèi)存。
3、不允許一個(gè)線(xiàn)程無(wú)原因地(沒(méi)有發(fā)生過(guò)任何assign操作)把數(shù)據(jù)從線(xiàn)程的工作內(nèi)存同步回主內(nèi)存中。
4、一個(gè)新的變量只能從主內(nèi)存中“誕生”,不允許在工作內(nèi)存中直接使用一個(gè)未被初始化(load或assign)的變量,換句話(huà)說(shuō)就是對(duì)一個(gè)變量實(shí)施use和store操作之前,必須先執(zhí)行過(guò)了assign和load操作。
5、一個(gè)變量在同一個(gè)時(shí)刻只允許一條線(xiàn)程對(duì)其執(zhí)行l(wèi)ock操作,但lock操作可以被同一個(gè)條線(xiàn)程重復(fù)執(zhí)行多次,多次執(zhí)行l(wèi)ock后,只有執(zhí)行相同次數(shù)的unlock操作,變量才會(huì)被解鎖。
6、如果對(duì)一個(gè)變量執(zhí)行l(wèi)ock操作,將會(huì)清空工作內(nèi)存中此變量的值,在執(zhí)行引擎使用這個(gè)變量前,需要重新執(zhí)行l(wèi)oad或assign操作初始化變量的值。
7、如果一個(gè)變量實(shí)現(xiàn)沒(méi)有被lock操作鎖定,則不允許對(duì)它執(zhí)行unlock操作,也不允許去unlock一個(gè)被其他線(xiàn)程鎖定的變量。
8、對(duì)一個(gè)變量執(zhí)行unlock操作之前,必須先把此變量同步回主內(nèi)存(執(zhí)行store和write操作)。
程序次序規(guī)則(PRogram Order Rule):在一個(gè)線(xiàn)程中,按照程序代碼順序,書(shū)寫(xiě)在前面的代碼操作先行發(fā)生于后面的操作
管程鎖定規(guī)則(Monitor Lock Rule):一個(gè) unlock 操作先行發(fā)生于后面對(duì)同一個(gè)鎖的 lock 操作。“后面”指的是時(shí)間的先后順序。
volatile 變量規(guī)則(Volatile Variable Rule):對(duì)一個(gè) volatile 變量的寫(xiě)操作先行發(fā)生于后面對(duì)這個(gè)變量的讀操作。“后面”指的是時(shí)間的先后順序。
線(xiàn)程啟動(dòng)規(guī)則(Thread Start Rule):Thread 對(duì)象的 start() 方法先行發(fā)生于此線(xiàn)程的每一個(gè)動(dòng)作。
線(xiàn)程終止規(guī)則(Thread Termination Rule):線(xiàn)程中所有操作先行發(fā)生于對(duì)此線(xiàn)程的終止檢測(cè)。
線(xiàn)程中斷規(guī)則(Thread Interruption Rule):對(duì)線(xiàn)程 interrupt() 方法的調(diào)用先行發(fā)生于代碼檢測(cè)到中斷事件的發(fā)生。
對(duì)象終結(jié)規(guī)則(Finalizer Rule):一個(gè)對(duì)象的初始化完成(構(gòu)造函數(shù)結(jié)束)先行發(fā)生于它的 finalize() 方法的開(kāi)始。
傳遞性(Transitivity):如果操作A先行發(fā)生于操作B,操作B先行發(fā)生于操作C,那么操作A先行發(fā)生于操作C。
時(shí)間的先后與先行發(fā)生原則并沒(méi)有太多關(guān)系1、保證可見(jiàn)性,也就是說(shuō)對(duì)volatile變量進(jìn)行寫(xiě)入操作的時(shí)候,其它線(xiàn)程能立即看到變化,而普通變量是做不到的。實(shí)現(xiàn)的原理就是volatile變量每次使用前都會(huì)去刷新,而每次寫(xiě)入都會(huì)實(shí)時(shí)同步到主內(nèi)存中。
2、volatile變量并不是并發(fā)安全的,雖然我們能立即看到volatile變量的最新值,但volatile變量參與的運(yùn)算,并不是一個(gè)原子操作。
volatile變量適用的場(chǎng)景就是一個(gè)控制線(xiàn)程操作,其它work線(xiàn)程依賴(lài)它來(lái)進(jìn)行決策,這種情況下不需要用鎖就能實(shí)現(xiàn)并發(fā)安全的效果
硬件支持的組合原子指令(CAS)是實(shí)現(xiàn)基礎(chǔ),如:
測(cè)試并設(shè)置;
獲取并增加;
交換;
比較并交換;
加載鏈條/條件存儲(chǔ);
鎖作為最常用保證線(xiàn)程安全的工具,用的不好會(huì)導(dǎo)致死鎖,或者本來(lái)可以并發(fā)的變成了串行,降低了執(zhí)行效率。
死鎖問(wèn)題靠的是編碼邏輯實(shí)現(xiàn)的謹(jǐn)慎,而鎖的優(yōu)化,則能大大的降低鎖對(duì)程序效率的影響。
1、自旋鎖與自適應(yīng)自旋;
不讓出對(duì)CPU的占用時(shí)間,而是循環(huán)等待獲得對(duì)應(yīng)的鎖。如果鎖占用時(shí)間很短,自旋等待的效果就會(huì)非常好;反之,如果鎖被占用的時(shí)間特別長(zhǎng),那么自旋的線(xiàn)程只會(huì)白白的浪費(fèi)處理器資源,而不會(huì)做任何有用的工作,反而會(huì)帶來(lái)性能上的浪費(fèi);我的理解是如果自旋的時(shí)間比線(xiàn)程上下文切換的代價(jià)還要大,就不如直接阻塞而不是自旋了。
2、鎖消除;
虛擬機(jī)檢測(cè)到一段代碼上不存在共享數(shù)據(jù)競(jìng)爭(zhēng)的問(wèn)題,就會(huì)把鎖消除;
3、鎖粗化;
一般我們是盡量把鎖的范圍減小。但是有時(shí)候反其道而行之也能提高效率,在一段代碼中反復(fù)對(duì)同一個(gè)鎖加鎖解鎖,就可以直接對(duì)整塊代碼加鎖,以減少操作鎖的開(kāi)銷(xiāo);
4、輕量級(jí)鎖;
5、偏向鎖;
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注