Java中synchronized鎖的深入理解
使用范圍
- synchronized使用上用于同步方法或者同步代碼塊
- 在鎖實(shí)現(xiàn)上是基于對(duì)象去實(shí)現(xiàn)
- 使用中用于對(duì)static修飾的便是class類鎖
- 使用中用于對(duì)非static修飾的便是當(dāng)前對(duì)象鎖

synchronized的優(yōu)化
- 在jdk1.6中對(duì)synchronized做了相關(guān)的優(yōu)化
鎖消除
- 在synchronized修飾的代碼塊中,要是不涉及操作臨界資源的情況,即便你寫了synchronized修飾,也不會(huì)出發(fā)鎖機(jī)制

鎖膨脹
- 在一個(gè)循環(huán)中頻繁的出現(xiàn)鎖資源的獲取與釋放操作,會(huì)帶來資源的消耗,于是便會(huì)將鎖的范圍擴(kuò)大到循環(huán)的外邊,避免頻繁的競(jìng)爭(zhēng)和獲取鎖資源而導(dǎo)致的資源消耗
public void method(){
for (int i = 0; i < Integer.MAX_VALUE; i++) {
synchronized ("") {
// 業(yè)務(wù)代碼
}
}
}

鎖升級(jí)
- ReentrantLock中是基于樂觀鎖的CAS獲取線程資源。資源拿不到的情況下才會(huì)掛起線程。synchronized在jdk1.6之間完全獲取不到鎖的情況下立即掛起線程,但是在1.6之后進(jìn)行了鎖的升級(jí)與優(yōu)化。
- 無鎖、匿名偏向:當(dāng)前對(duì)象沒有作為鎖的存在
- 偏向鎖:當(dāng)前鎖資源,只有一個(gè)線程頻繁的獲取和釋放鎖,那么只有該線程獲取鎖是判斷是否是同一個(gè)線程,如果是線程資源拿走。如果線程不是當(dāng)前自己的線程,則采用基于CAS的方式,嘗試將偏向鎖指向當(dāng)前線程。如果獲取不到則觸發(fā)鎖升級(jí)為輕量級(jí)鎖,也就意味著發(fā)生了鎖競(jìng)爭(zhēng)的情況。
- 輕量級(jí)鎖:使用自旋鎖的方式頻繁的采用CAS的方式獲取鎖資源。這里采用的自適應(yīng)自旋鎖(JVM更具上次的自旋結(jié)果來進(jìn)行判斷本次的自旋時(shí)間長(zhǎng)短)。如果成功獲取鎖資源,資源取走。如果獲取鎖資源失敗,鎖升級(jí)。
- 重量級(jí)鎖:最為傳統(tǒng)的synchronized實(shí)現(xiàn)方式。拿不到鎖資源之間掛起線程,然后進(jìn)行用戶態(tài)和內(nèi)核態(tài)的不斷切換。。。
synchronized鎖的實(shí)現(xiàn)原理
- synchronized鎖是基于對(duì)象來進(jìn)行實(shí)現(xiàn)的

- 關(guān)于MarkWord的內(nèi)容展開示意圖

- 從圖中可以看出通過鎖的標(biāo)志位來進(jìn)行區(qū)分鎖的不同狀態(tài)
synchronized鎖升級(jí)的過程演示
- 使用之前需要導(dǎo)入一個(gè)依賴
<dependency>
<groupId>org.openjdk.jol</groupId>
<artifactId>jol-core</artifactId>
<version>0.9</version>
</dependency>
- 鎖在默認(rèn)情況下,開啟了偏向鎖的延遲
- 原因是因?yàn)樵谄蜴i升級(jí)為輕量級(jí)鎖的時(shí)候會(huì)涉及到偏向鎖的撤銷,需要等到一個(gè)安全點(diǎn)(STW),才能完成對(duì)偏向鎖的撤銷,所以在并發(fā)的情況下就可以選擇不開啟偏向鎖,或者設(shè)置偏向鎖延遲開啟
- 在JVM啟動(dòng)時(shí)會(huì)大量加載.class文件到內(nèi)存,該操作會(huì)涉及synchronized使用,為了避免出現(xiàn)偏向鎖撤銷的操作。在啟動(dòng)初期,有一個(gè)延遲5s開啟偏向鎖的操作。
- 要是正常開啟偏向鎖,那么就不會(huì)出現(xiàn)無鎖的狀態(tài),而是直接進(jìn)入匿名偏向鎖

- 變成了偏向鎖

/**
* @author
* @date 2023/5/28
*/
public class Test15 {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(5000);
Object o = new Object();
System.out.println(ClassLayout.parseInstance(o).toPrintable());
//thread 線程偏向鎖
Thread thread = new Thread(()->{
synchronized (o){
System.out.println("thread線程 :"+ClassLayout.parseInstance(o).toPrintable());
}
});
thread.start();
// 輕量級(jí)鎖 -> 重量級(jí)鎖
synchronized (o){
System.out.println("main線程 :"+ClassLayout.parseInstance(o).toPrintable());
}
}
}
鎖轉(zhuǎn)換狀態(tài)示意圖

LockRecord和ObjectMonitor存儲(chǔ)的內(nèi)容示意圖

以上就是Java中synchronized鎖的深入理解的詳細(xì)內(nèi)容,更多關(guān)于Java synchronized鎖的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
java實(shí)現(xiàn)檢測(cè)Linux網(wǎng)絡(luò)狀態(tài)(附源碼)
實(shí)時(shí)監(jiān)控服務(wù)器網(wǎng)絡(luò)狀態(tài)是保證業(yè)務(wù)高可用性和可靠性的重要環(huán)節(jié),本文主要介紹了如何設(shè)計(jì)并實(shí)現(xiàn)一個(gè)高性能,可擴(kuò)展,支持事件訂閱與周期采樣的Linux?網(wǎng)絡(luò)狀態(tài)檢測(cè)工具,需要的可以了解下2025-06-06
Mysql?json類型字段Java+Mybatis數(shù)據(jù)字典功能的實(shí)踐方式
這篇文章主要介紹了Mysql?json類型字段Java+Mybatis數(shù)據(jù)字典功能的實(shí)踐方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-08-08
linux用java -jar啟動(dòng)jar包緩慢的問題
這篇文章主要介紹了linux用java -jar啟動(dòng)jar包緩慢的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,2023-09-09
Java實(shí)現(xiàn)多線程下載和斷點(diǎn)續(xù)傳
這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)多線程下載和斷點(diǎn)續(xù)傳,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06
SpringBoot項(xiàng)目網(wǎng)頁加載出現(xiàn)Whitelabel?Error?Page的解決
這篇文章主要介紹了SpringBoot項(xiàng)目網(wǎng)頁加載出現(xiàn)Whitelabel?Error?Page的解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-11-11
java開發(fā)之SQL語句中DATE_FORMAT函數(shù)舉例詳解
要將日期值格式化為特定格式,請(qǐng)使用DATE_FORMAT函數(shù),下面這篇文章主要給大家介紹了關(guān)于java開發(fā)之SQL語句中DATE_FORMAT函數(shù)的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2024-05-05
Java中的三種校驗(yàn)注解的使用(@Valid,@Validated和@PathVariable)
本文主要介紹了Java中的三種校驗(yàn)注解的使用(@Valid,@Validated和@PathVariable),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2022-04-04
數(shù)組在java中的擴(kuò)容的實(shí)例方法
在本篇文章里小編給大家分享的是一篇關(guān)于數(shù)組在java中的擴(kuò)容的實(shí)例方法內(nèi)容,有興趣的朋友們可以學(xué)習(xí)下。2021-01-01

