Synchronized:
(1)jdk1.2之前synchronized 加鎖是直接向操作系統(tǒng)直接申請(qǐng)鎖筐钟,所以我們稱(chēng)為重量級(jí)鎖京痢。
1.2之后synchronized做了優(yōu)化募疮,根據(jù)并發(fā)訪(fǎng)問(wèn)量控制鎖升級(jí)的過(guò)程草讶;
(2)CAS:底層使用 lock cmpxchg 指令 (cmpxchg由于不是原子性逝嚎,前面加上lock)
(3)用戶(hù)態(tài)和內(nèi)核態(tài):針對(duì)區(qū)分執(zhí)行的指令岛蚤;用戶(hù)空間的進(jìn)程只能調(diào)用用戶(hù)態(tài)的指令;所有的操作指令cpu內(nèi)核都能調(diào)用
(4) 鎖升級(jí)的過(guò)程
當(dāng)我們對(duì)一個(gè)對(duì)象加鎖其實(shí)是修改這個(gè)對(duì)象的markword信息懈糯;
當(dāng)我new 出一個(gè)對(duì)象可能有兩種狀態(tài)涤妒,偏向鎖已經(jīng)啟動(dòng)和未啟動(dòng) ;
普通我們new出一個(gè)對(duì)象赚哗,加上synchronized ,如果偏向鎖已經(jīng)啟動(dòng)她紫,升級(jí)為偏向鎖;
如果偏向鎖沒(méi)有啟動(dòng)屿储,直接到自旋鎖贿讹;
一旦有另外線(xiàn)程搶占資源,升級(jí)為輕量級(jí)鎖(自旋鎖CAS)够掠;
偏向鎖到輕量級(jí)鎖的過(guò)程:有兩個(gè)線(xiàn)程搶占一把鎖民褂,都會(huì)在本地線(xiàn)程內(nèi)生成一個(gè)LockRecord ,自旋(CAS操作)去搶占這把鎖,一旦有那個(gè)線(xiàn)程拿到這把鎖疯潭,這個(gè)鎖上有該線(xiàn)程的指針指向?qū)?yīng)線(xiàn)程的LockRecord赊堪;未搶到鎖的線(xiàn)程繼續(xù)CAS操作申請(qǐng)這把鎖(用戶(hù)態(tài)鎖)
偏向鎖默認(rèn)JVM啟動(dòng)后4秒啟動(dòng),也可以通過(guò) -XX:BiasedLockingStartupDelay=0指定是否開(kāi)啟
競(jìng)爭(zhēng)激烈升級(jí)為重量級(jí)鎖竖哩,1.6以前自旋10次(可以通過(guò)-XX:PreBlockSpin)哭廉,或者超過(guò)CPU核數(shù)1/2;1.6以后是自適應(yīng)自旋相叁,JVM自己控制
jvm通過(guò)C++的objectMonitor對(duì)象遵绰,去操作系統(tǒng)申請(qǐng)鎖辽幌,并記錄到markword中
5)鎖的底層代碼邏輯實(shí)現(xiàn)
加上synchronized代碼塊,匯編碼會(huì)生成一個(gè)monitorenter 指令開(kāi)始加鎖椿访,montorexit鎖釋放
monitorenter 匯編方法中先判斷是否是使用偏向鎖乌企,如果是進(jìn)入fast_enter,快速拿到鎖,不需要競(jìng)爭(zhēng)成玫;如果不是進(jìn)入slow_enter方法逛犹,先自旋拿鎖,自旋到一定的次數(shù)膨脹梁剔,調(diào)用
inflate方法去拿重量級(jí)鎖
6)synchronized 是可重入鎖
重入次數(shù)必須記錄虽画,因?yàn)橐怄i幾次必須得到對(duì)應(yīng)
偏向鎖和自旋鎖->線(xiàn)程棧 ->記錄一個(gè)lockrecord 并+1
重量級(jí)鎖->C++對(duì)象ObjectMonitor的一個(gè)字段屬性上
(7)為什么有自旋鎖還要重量級(jí)鎖?
因?yàn)樽孕i是需要暫用CPU資源荣病,那鎖過(guò)長(zhǎng)码撰,或者自旋線(xiàn)程速過(guò)多,占用大量CPU資源
重量級(jí)鎖里面會(huì)有等待隊(duì)列个盆,不占額外的資源