前言
到這里,大家應(yīng)該都知道唧取,Java中都有哪些鎖铅鲤,做什么用的了;
那么兵怯,不知道大家有沒(méi)有聽(tīng)過(guò)Java鎖的膨脹機(jī)制彩匕?
synchronized
JDK1.6 前只有重量級(jí)鎖,JDK1.6之后媒区,jvm對(duì)其進(jìn)行優(yōu)化驼仪,增加了偏向鎖和輕量級(jí)鎖(這兩種鎖咱們?cè)谏弦黄呀?jīng)解釋過(guò)了,就不在復(fù)述了)袜漩;
對(duì)象頭
了解鎖膨脹之前绪爸,咱們需要先了解下對(duì)象頭;
在JVM的實(shí)現(xiàn)中每一個(gè)對(duì)象都會(huì)有一個(gè)對(duì)象頭宙攻,它是用于保存對(duì)象的系統(tǒng)信息奠货,對(duì)象頭中有一個(gè)官方稱為 MarkDown 的部分,他就是實(shí)現(xiàn)各種鎖的關(guān)鍵座掘;
在32位系統(tǒng)里递惋,MarkDown 是32位的數(shù)據(jù),64位系統(tǒng)中是64位的數(shù)據(jù)溢陪;
存放了對(duì)象的哈希值萍虽、對(duì)象年齡、鎖的指針等等信息形真,總之就是一個(gè)對(duì)象的鎖是否被占用杉编、占用的是哪種鎖,就記錄在MarkDown中咆霜;
synchronized 升級(jí)之一階段(偏向鎖)
當(dāng)線程訪問(wèn)同步代碼塊并獲取鎖時(shí)邓馒,會(huì)在 Mark Word 里存儲(chǔ)鎖偏向的線程 ID;
在線程進(jìn)入和退出同步塊時(shí)不再通過(guò) CAS 操作來(lái)加鎖和解鎖蛾坯,而是檢測(cè) Mark Word 里是否存儲(chǔ)著指向當(dāng)前線程的偏向鎖光酣;
偏向鎖只有遇到其他線程嘗試競(jìng)爭(zhēng)偏向鎖時(shí),持有偏向鎖的線程才會(huì)釋放鎖脉课,線程是不會(huì)主動(dòng)釋放偏向鎖的救军;
偏向鎖的撤銷(xiāo):
- 在某個(gè)時(shí)間點(diǎn)上沒(méi)有字節(jié)碼正在執(zhí)行時(shí)改览,它會(huì)先暫停擁有偏向鎖的線程,然后判斷鎖對(duì)象是否處于被鎖定狀態(tài)
- 線程不處于活動(dòng)狀態(tài)缤言,則將對(duì)象頭設(shè)置成無(wú)鎖狀態(tài),并撤銷(xiāo)偏向鎖视事,恢復(fù)到無(wú)鎖(標(biāo)志位為01)或輕量級(jí)鎖(標(biāo)志位為00)的狀態(tài)
JVM 參數(shù):
關(guān)閉偏向鎖:-XX:-UseBiasedLocking=false胆萧,關(guān)閉之后程序默認(rèn)會(huì)進(jìn)入輕量級(jí)鎖狀態(tài)
synchronized 升級(jí)之二階段(輕量級(jí)鎖)
輕量級(jí)鎖是指當(dāng)鎖是偏向鎖的時(shí)候,卻被另外的線程所訪問(wèn)俐东,此時(shí)偏向鎖就會(huì)升級(jí)為輕量級(jí)鎖跌穗,其他線程會(huì)通過(guò)自旋的形式嘗試獲取鎖,線程不會(huì)阻塞虏辫,從而提高性能蚌吸;
升級(jí)過(guò)程:
- 線程在自己的棧楨中創(chuàng)建鎖記錄 LockRecord
- 將鎖對(duì)象的對(duì)象頭中的MarkWord復(fù)制到線程的剛剛創(chuàng)建的鎖記錄中
- 將鎖記錄中的Owner指針指向鎖對(duì)象
- 將鎖對(duì)象的對(duì)象頭的MarkWord替換為指向鎖記錄的指針,并將對(duì)象 Mark Word 的鎖標(biāo)志位設(shè)置為“00”砌庄,表示此對(duì)象處于輕量級(jí)鎖定狀態(tài)
出現(xiàn)輕量級(jí)鎖的兩種情況:
- 當(dāng)關(guān)閉偏向鎖功能時(shí)
- 多個(gè)線程競(jìng)爭(zhēng)偏向鎖導(dǎo)致偏向鎖升級(jí)為輕量級(jí)鎖
輕量級(jí)鎖: CAS 操作和自旋來(lái)解決加鎖問(wèn)題羹唠,避免線程阻塞和喚醒而影響性能;
輕量級(jí)鎖再次膨脹情況:
- 若當(dāng)前只有一個(gè)等待線程娄昆,則該線程將通過(guò)自旋進(jìn)行等待佩微。但是當(dāng)自旋超過(guò)一定的次數(shù)時(shí),輕量級(jí)鎖便會(huì)升級(jí)為重量級(jí)鎖
- 當(dāng)一個(gè)線程已持有鎖萌焰,另一個(gè)線程在自旋哺眯,而此時(shí)又有第三個(gè)線程來(lái)訪時(shí),輕量級(jí)鎖也會(huì)升級(jí)為重量級(jí)鎖
synchronized 升級(jí)之三階段(重量級(jí)鎖)
重量級(jí)鎖是依賴對(duì)象內(nèi)部的monitor鎖來(lái)實(shí)現(xiàn)的扒俯,而monitor又依賴操作系統(tǒng)的MutexLock(互斥鎖)來(lái)實(shí)現(xiàn)的奶卓,所以重量級(jí)鎖也被成為互斥鎖;
當(dāng)有一個(gè)線程獲取重量級(jí)鎖之后撼玄,其余所有等待獲取該鎖的線程都會(huì)處于阻塞狀態(tài)夺姑,操作系統(tǒng)實(shí)現(xiàn)線程之間的切換需要從用戶態(tài)切換到內(nèi)核態(tài),而轉(zhuǎn)換狀態(tài)是需要消耗很多時(shí)間的互纯,有可能比用戶執(zhí)行代碼的時(shí)間還要長(zhǎng)瑟幕,所以它的切換成本非常高,這同時(shí)也說(shuō)明了為什么重量級(jí)線程開(kāi)銷(xiāo)很大
的原因留潦;
總結(jié)
通過(guò)上面的分析只盹,我們知道了 synchronized 鎖的演變過(guò)程,這就告訴我們兔院,假如一開(kāi)始就知道某個(gè)同步代碼塊的競(jìng)爭(zhēng)很激烈殖卑,那么一開(kāi)始就應(yīng)該使用重量級(jí)鎖了,節(jié)省掉一些鎖轉(zhuǎn)換的開(kāi)銷(xiāo)坊萝。