JDK6對(duì)Synchronized進(jìn)行了優(yōu)化丧鸯,不再默認(rèn)是重量級(jí)鎖帚称,有了鎖升級(jí)過程咧纠。
1蓬痒、無鎖 → 偏向鎖
因?yàn)榻?jīng)過HotSpot的作者大量的研究發(fā)現(xiàn),大多數(shù)時(shí)候是不存在鎖競(jìng)爭(zhēng)的漆羔,常常是一個(gè)線程多次獲得同一個(gè)鎖梧奢,因此如果每次都要競(jìng)爭(zhēng)鎖會(huì)增大很多沒有必要付出的代價(jià),為了降低獲取鎖的代價(jià)演痒,才引入的偏向鎖亲轨。
如果一塊臨界區(qū)從未被任何線程訪問過,則它就一直處于無鎖狀態(tài)嫡霞。當(dāng)?shù)谝粋€(gè)線程來訪問它時(shí)瓶埋,這時(shí)候線程會(huì)判斷鎖狀態(tài)標(biāo)志位為01偏向標(biāo)志位為0,表示無鎖且可以使用偏向鎖诊沪。這時(shí)就會(huì)啟動(dòng)加偏向鎖的過程:
- 將偏向標(biāo)志位設(shè)置為1
- 使用CAS操作將線程ID寫入對(duì)象頭
如果CAS操作成功养筒,則該線程就獲取到了偏向鎖,該線程每次進(jìn)入同步塊時(shí)就再也不用加鎖解鎖了端姚。如果CAS操作失敗晕粪,說明發(fā)生了鎖競(jìng)爭(zhēng)胳岂,進(jìn)入升級(jí)輕量級(jí)鎖過程迫皱。
使用參數(shù)-XX:BiasedLockingStartupDelay可以設(shè)置偏向鎖開啟的延遲時(shí)間命浴,默認(rèn)為4秒厕倍,表示程序運(yùn)行4秒后才會(huì)啟用偏向鎖。原因在于尚氛,系統(tǒng)剛啟動(dòng)時(shí)诀诊,一般數(shù)據(jù)競(jìng)爭(zhēng)是比較激烈的,此時(shí)啟用偏向鎖會(huì)降低性能阅嘶。未開啟偏向鎖時(shí)的鎖升級(jí)過程為:無鎖→輕量級(jí)鎖→重量級(jí)鎖属瓣。
2、偏向鎖 → 輕量級(jí)鎖
輕量級(jí)鎖考慮的是競(jìng)爭(zhēng)鎖對(duì)象的線程不多讯柔,而且線程持有鎖的時(shí)間也不長(zhǎng)的情景抡蛙。因?yàn)樽枞€程需要CPU從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),代價(jià)較大魂迄,如果剛剛阻塞不久這個(gè)鎖就被釋放了粗截,那這個(gè)代價(jià)就有點(diǎn)得不償失了,因此這個(gè)時(shí)候就干脆不阻塞這個(gè)線程捣炬,讓它自旋著等待鎖釋放熊昌。
當(dāng)?shù)诙€(gè)線程嘗試獲取已被置為偏向的鎖時(shí),偏向模式就馬上宣告結(jié)束遥金。根據(jù)鎖對(duì)象目前是否處于被鎖定的狀態(tài)來決定是否撤銷偏向(偏向標(biāo)志設(shè)為0)浴捆,撤銷后鎖標(biāo)志位恢復(fù)到未鎖定或輕量級(jí)鎖的狀態(tài)。如果對(duì)象處于鎖定狀態(tài)稿械,則直接將鎖升級(jí)到重量級(jí)鎖选泻,否則由當(dāng)前試圖訪問到線程加上輕量級(jí)鎖。輕量級(jí)鎖的加鎖過程如下:
- 將鎖標(biāo)志位設(shè)置為00美莫,表示輕量級(jí)鎖
- 在當(dāng)前線程的棧幀中開辟一片空間存儲(chǔ)Mark Word
- 通過CAS操作將對(duì)象頭的信息替換為棧幀中存儲(chǔ)備份的地址
3页眯、輕量級(jí)鎖 → 重量級(jí)鎖
如果出現(xiàn)兩個(gè)以上的線程爭(zhēng)用同一個(gè)鎖的情況,那輕量級(jí)鎖就不再有效厢呵,必須要膨脹為重量級(jí)鎖窝撵,鎖標(biāo)志位狀態(tài)改為10,此時(shí)Mark Word中存儲(chǔ)的就是指向重量級(jí)鎖的指針襟铭,后面等待鎖的線程也不許進(jìn)入阻塞狀態(tài)碌奉。
References
http://www.reibang.com/p/ee02e710a8b9
https://zhuanlan.zhihu.com/p/187460479