1.對象被創(chuàng)建在堆中。并且對象在內(nèi)存中的存儲(chǔ)布局方式可以分為3塊區(qū)域:對象頭、實(shí)例數(shù)據(jù)、對齊填充。對象頭在64位的虛擬機(jī)里邊占用的是8個(gè)字節(jié),96byte,對于對象頭來說,主要是包括倆部分信息:
1.自身運(yùn)行時(shí)的數(shù)據(jù),比如:鎖狀態(tài)標(biāo)志、線程持有的鎖…等等。(此部分內(nèi)容被稱之為Mark Word)

2.另一部分是類型指針( Class Metadata Address ):JVM通過這個(gè)指針來確定這個(gè)對象是哪個(gè)類的實(shí)例。
synchronized鎖的宏觀實(shí)現(xiàn)
synchronized的對象鎖,其指針指向的是一個(gè)monitor對象(由C++實(shí)現(xiàn))的起始地址。每個(gè)對象實(shí)例都會(huì)有一個(gè) monitor。其中monitor可以與對象一起創(chuàng)建、銷毀;亦或者當(dāng)線程試圖獲取對象鎖時(shí)自動(dòng)生成。
monitor是由ObjectMonitor實(shí)現(xiàn)(ObjectMonitor.hpp文件,C++實(shí)現(xiàn)的),對于我們來說主要關(guān)注的是如下代碼

讓我們先看一下_owner,它指向持有ObjectMonitor對象的線程。當(dāng)多個(gè)線程同時(shí)訪問一段同步代碼時(shí),會(huì)先存放到 _EntryList 集合中,接下來當(dāng)線程獲取到對象的monitor時(shí),就會(huì)把_owner變量設(shè)置為當(dāng)前線程。同時(shí)count變量+1。如果線程調(diào)用wait() 方法,就會(huì)釋放當(dāng)前持有的monitor,那么_owner變量就會(huì)被置為null,同時(shí)_count減1,并且該線程進(jìn)入 WaitSet集合中,等待下一次被喚醒
當(dāng)然,若當(dāng)前線程順利執(zhí)行完方法,也將釋放monitor,重走一遍剛才的內(nèi)容,也就是_owner變量就會(huì)被置為null,同時(shí)_count減1,并且該線程進(jìn)入 WaitSet集合中,等待下一次被喚醒
因?yàn)檫@個(gè)鎖對象存放在對象本身,也就是為什么Java中任意對象可以作為鎖的原因
例子:


根據(jù)虛擬機(jī)規(guī)范要求,在執(zhí)行monitorenter指令時(shí),首先要嘗試獲取對象鎖,也就是上文我們提到了monitor對象。如果這個(gè)對象沒有被鎖定,或者當(dāng)前線程已經(jīng)擁有了這個(gè)對象的鎖,那么就把鎖的計(jì)數(shù)器(_count)加1。當(dāng)然與之對應(yīng)執(zhí)行monitorexit指令時(shí),鎖的計(jì)數(shù)器(_count)也會(huì)減1。
如果當(dāng)前線程獲取鎖失敗,那么就會(huì)被阻塞住,進(jìn)入_WaitSet 中,等待鎖被釋放為止。
?。。∽止?jié)碼中,有倆個(gè)monitorexit指令,這是為什么呢?
是這樣的,編譯器需要確保方法中調(diào)用過的每條monitorenter指令都要執(zhí)行對應(yīng)的monitorexit 指令。為了保證在方法異常時(shí),monitorenter和monitorexit指令也能正常配對執(zhí)行,編譯器會(huì)自動(dòng)產(chǎn)生一個(gè)異常處理器,它的目的就是用來執(zhí)行 異常的monitorexit指令。而字節(jié)碼中多出的monitorexit指令,就是異常結(jié)束時(shí),被執(zhí)行用來釋放monitor的。
?。?! 同步代碼塊和直接修飾在方法上有什么區(qū)別

可以看到:字節(jié)碼中并沒有monitorenter指令和monitorexit指令,取得代之的是ACC_SYNCHRONIZED標(biāo)識(shí),JVM通過ACC_SYNCHRONIZED標(biāo)識(shí),就可以知道這是一個(gè)需要同步的方法,進(jìn)而執(zhí)行上述同步的過程,也就是_count加1,這些過程。
notify/notifyAll/wait等方法存在于頂級對象Object中的原因,在使用這3個(gè)方法時(shí),必須處于synchronized代碼塊或者synchronized方法中,否則就會(huì)拋出IllegalMonitorStateException異常,
我們知道m(xù)onitor 存在于對象頭的Mark Word 中(存儲(chǔ)monitor引用指針),而synchronized關(guān)鍵字可以獲取 monitor ,這也就是為什么notify/notifyAll和wait方法必須在synchronized代碼塊或者synchronized方法調(diào)用的原因