最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java?synchronized關(guān)鍵字用法和底層原理舉例詳解

 更新時(shí)間:2026年01月30日 08:19:44   作者:看透也說(shuō)透kevin  
synchronized關(guān)鍵字是java語(yǔ)言進(jìn)行多線程編程,非常常用的關(guān)鍵,這篇文章主要介紹了java?synchronized關(guān)鍵字用法和底層原理的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下

一、synchronized的用法

synchronized 關(guān)鍵字用于實(shí)現(xiàn)線程同步,確保多個(gè)線程在訪問(wèn)共享資源時(shí)不會(huì)發(fā)生數(shù)據(jù)競(jìng)爭(zhēng)和不一致的問(wèn)題。它主要有三種使用方式:

1. 同步實(shí)例方法

public synchronized void method() {
    // 同步代碼
}
  • 鎖對(duì)象是當(dāng)前實(shí)例(this)。
  • 同一個(gè)實(shí)例的多個(gè)線程調(diào)用此方法時(shí)會(huì)互斥。

2. 同步靜態(tài)方法

public static synchronized void staticMethod() {
    // 同步代碼
}
  • 鎖對(duì)象是當(dāng)前類的 Class 對(duì)象(如 MyClass.class)。
  • 所有實(shí)例的線程調(diào)用此方法時(shí)都會(huì)互斥。

3. 同步代碼塊

synchronized (lockObject) {
    // 同步代碼
}
  • 可以靈活指定鎖對(duì)象(可以是任意對(duì)象)。
  • 縮小了同步范圍,提高性能。

4. 深入:wait(),notify(),notifyAll()

這三個(gè)方法是定義在 Object 類中的本地方法,必須在一個(gè)同步代碼塊或同步方法內(nèi)(即已經(jīng)持有該對(duì)象的監(jiān)視器鎖)調(diào)用,否則會(huì)拋出 IllegalMonitorStateException 異常。它們與 synchronized 配合使用,實(shí)現(xiàn)線程間的協(xié)調(diào)(等待/通知機(jī)制)。

  • wait(): 使當(dāng)前線程釋放其持有的對(duì)象鎖,并進(jìn)入等待狀態(tài)(WAITING),直到其他線程調(diào)用該對(duì)象的 notify()notifyAll() 方法,或被中斷。調(diào)用后,線程會(huì)釋放鎖。
  • notify(): 隨機(jī)喚醒一個(gè)正在等待該對(duì)象鎖的線程。被喚醒的線程會(huì)從等待池移動(dòng)到阻塞隊(duì)列(EntryList)中,等待鎖釋放后重新競(jìng)爭(zhēng)鎖。
  • notifyAll(): 喚醒所有正在等待該對(duì)象鎖的線程。這些線程都會(huì)被移動(dòng)到阻塞隊(duì)列中,共同競(jìng)爭(zhēng)鎖。

典型的生產(chǎn)者-消費(fèi)者模式示例:

public class WaitNotifyExample {
    private final Object lock = new Object();
    private boolean conditionMet = false;

    public void consumer() throws InterruptedException {
        synchronized (lock) {
            // 使用while循環(huán)防止"虛假喚醒"
            while (!conditionMet) {
                lock.wait(); // 釋放lock鎖,當(dāng)前線程進(jìn)入等待
            }
            // 條件滿足,執(zhí)行消費(fèi)任務(wù)
            System.out.println("Consuming...");
            conditionMet = false;
            lock.notifyAll(); // 消費(fèi)完成,通知生產(chǎn)者
        }
    }

    public void producer() throws InterruptedException {
        synchronized (lock) {
            while (conditionMet) {
                lock.wait(); // 如果條件已滿足,則等待消費(fèi)者消費(fèi)
            }
            // 生產(chǎn)任務(wù)
            System.out.println("Producing...");
            conditionMet = true;
            lock.notifyAll(); // 生產(chǎn)完成,通知消費(fèi)者
        }
    }
}

關(guān)鍵點(diǎn):

  1. 總是需要在循環(huán)中調(diào)用 wait() 以防止虛假喚醒(Spurious Wakeup),即線程可能在沒有被通知、中斷或超時(shí)的情況下醒來(lái)。
  2. wait() 會(huì)釋放鎖,而 sleep() 不會(huì)。
  3. 通常更推薦使用 notifyAll(),因?yàn)?notify() 是隨機(jī)喚醒,可能導(dǎo)致某些線程永遠(yuǎn)無(wú)法被喚醒(線程饑餓)。

二、底層原理

synchronized 的底層實(shí)現(xiàn)依賴于 JVM 內(nèi)部的 監(jiān)視器鎖(Monitor) 機(jī)制,主要涉及以下概念:

1. 對(duì)象頭與 Mark Word

  • 在 HotSpot 虛擬機(jī)中,每個(gè)對(duì)象都有一個(gè)對(duì)象頭,其中包含 Mark Word(標(biāo)記字段)。
  • Mark Word 的長(zhǎng)度為 32位 或 64位,用于存儲(chǔ)對(duì)象的哈希碼、分代年齡、鎖狀態(tài)標(biāo)志位等信息。鎖的狀態(tài)就記錄在這里。

2. 鎖升級(jí)的詳細(xì)過(guò)程

為了平衡性能與安全性,JVM 對(duì) synchronized 進(jìn)行了優(yōu)化,引入了鎖升級(jí)機(jī)制。這個(gè)過(guò)程是單向的:無(wú)鎖 → 偏向鎖 → 輕量級(jí)鎖 → 重量級(jí)鎖。

  1. 無(wú)鎖狀態(tài) (01)

    • 初始狀態(tài),對(duì)象剛被創(chuàng)建,尚未有任何線程競(jìng)爭(zhēng)。
  2. 偏向鎖 (Biased Locking) (01)

    • 目的:消除在無(wú)競(jìng)爭(zhēng)情況下的同步開銷。假設(shè)在大多數(shù)情況下,鎖不僅不存在多線程競(jìng)爭(zhēng),而且總是由同一線程多次獲得。
    • 流程
      • 加鎖:當(dāng)一個(gè)線程第一次訪問(wèn)同步塊時(shí),它會(huì)通過(guò) CAS 操作將自己的 線程ID 寫入對(duì)象頭的 Mark Word。如果成功,則進(jìn)入偏向模式,鎖標(biāo)志位變?yōu)?01,且偏向模式標(biāo)志為 1。
      • 執(zhí)行:此后,只要這個(gè)線程再次進(jìn)入同步塊,只需檢查 Mark Word 中的線程ID是否是自己。如果是,則無(wú)需任何同步操作(如CAS、系統(tǒng)互斥)直接執(zhí)行,極大提升性能。
      • 撤銷:一旦出現(xiàn)另一個(gè)線程來(lái)嘗試競(jìng)爭(zhēng)鎖,偏向鎖就會(huì)撤銷(Revoke Bias)。撤銷過(guò)程需要等待全局安全點(diǎn)(STW),然后檢查原持有偏向鎖的線程是否仍活躍。如果活躍,則鎖升級(jí)為輕量級(jí)鎖;如果已不活躍,則可將對(duì)象置為無(wú)鎖狀態(tài),重新偏向新的線程。
  3. 輕量級(jí)鎖 (Lightweight Locking) (00)

    • 目的:在有多線程競(jìng)爭(zhēng),但競(jìng)爭(zhēng)時(shí)間錯(cuò)開(即近乎交替執(zhí)行)的場(chǎng)景下,避免線程直接進(jìn)入阻塞,減少用戶態(tài)到內(nèi)核態(tài)的切換開銷。
    • 加鎖流程
      • 線程在執(zhí)行同步塊之前,JVM 會(huì)先在當(dāng)前線程的棧幀中創(chuàng)建一個(gè)名為鎖記錄(Lock Record) 的空間。
      • 將對(duì)象頭的 Mark Word 復(fù)制到線程的鎖記錄中(稱為 Displaced Mark Word)。
      • 線程嘗試通過(guò) CAS 操作將對(duì)象頭的 Mark Word 替換為指向其鎖記錄的指針。
      • 如果成功,當(dāng)前線程獲得鎖,鎖標(biāo)志位變?yōu)?00。
      • 如果失敗,表示至少有一條線程與當(dāng)前線程競(jìng)爭(zhēng),當(dāng)前線程會(huì)嘗試自旋(循環(huán)重試CAS操作)來(lái)獲取鎖。
    • 解鎖流程
      • 使用 CAS 操作將 Displaced Mark Word 替換回對(duì)象頭。
      • 如果成功,表示沒有競(jìng)爭(zhēng)發(fā)生。
      • 如果失敗,表示當(dāng)前鎖存在競(jìng)爭(zhēng),鎖會(huì)膨脹為重量級(jí)鎖,并在解鎖時(shí)喚醒等待的線程。
    • 自旋優(yōu)化:線程不會(huì)立即阻塞,而是循環(huán)嘗試獲取鎖。避免了線程上下文切換的開銷,但會(huì)消耗CPU。如果自旋過(guò)度(如自旋次數(shù)超過(guò)閾值,或競(jìng)爭(zhēng)的線程數(shù)過(guò)多),鎖會(huì)直接升級(jí)為重量級(jí)鎖。
  4. 重量級(jí)鎖 (Heavyweight Locking) (10)

    • 目的:處理高并發(fā)、激烈競(jìng)爭(zhēng)的場(chǎng)景。
    • 流程:當(dāng)輕量級(jí)鎖競(jìng)爭(zhēng)失敗后,會(huì)膨脹為重量級(jí)鎖。此時(shí),Mark Word 中存儲(chǔ)的是指向一個(gè)互斥量(Mutex) 的指針,這個(gè)互斥量由操作系統(tǒng)內(nèi)核提供。
    • 所有等待鎖的線程都會(huì)進(jìn)入阻塞狀態(tài)(BLOCKED),不再消耗CPU。鎖的獲取和釋放需要操作系統(tǒng)進(jìn)行線程的掛起喚醒,這個(gè)過(guò)程涉及到復(fù)雜的用戶態(tài)到內(nèi)核態(tài)的切換,開銷最大。

鎖升級(jí)狀態(tài)總結(jié)表:

鎖狀態(tài)存儲(chǔ)內(nèi)容標(biāo)志位適用場(chǎng)景
無(wú)鎖對(duì)象的哈希碼、分代年齡等01無(wú)競(jìng)爭(zhēng)
偏向鎖持有偏向鎖的線程ID、Epoch、分代年齡、偏向模式標(biāo)志 101只有一個(gè)線程訪問(wèn)同步塊
輕量級(jí)鎖指向棧中鎖記錄的指針00多個(gè)線程交替訪問(wèn),低并發(fā)競(jìng)爭(zhēng)
重量級(jí)鎖指向互斥量(Mutex)的指針10高并發(fā)激烈競(jìng)爭(zhēng)

3. 底層指令

  • 同步代碼塊通過(guò) monitorentermonitorexit 指令實(shí)現(xiàn):
    • 進(jìn)入同步塊時(shí)執(zhí)行 monitorenter,退出時(shí)執(zhí)行 monitorexit(包括正常退出和異常退出)。
  • 同步方法通過(guò)方法表中的 ACC_SYNCHRONIZED 標(biāo)志標(biāo)識(shí),JVM通過(guò)此標(biāo)志判斷是否需要同步。

三、注意事項(xiàng)

  1. 可重入性synchronized 是可重入鎖,同一線程可多次獲取同一把鎖。
  2. 鎖對(duì)象不能為 null:同步代碼塊的鎖對(duì)象不能是 null,否則會(huì)拋出 NullPointerException。
  3. 性能考慮
    • 盡量減小同步范圍(使用代碼塊而非整個(gè)方法)。
    • 避免鎖競(jìng)爭(zhēng)激烈,否則會(huì)升級(jí)為重量級(jí)鎖,降低性能。
  4. 與 Lock 的區(qū)別
    • synchronized 是關(guān)鍵字,JVM 級(jí)別實(shí)現(xiàn);Lock 是 API 級(jí)別實(shí)現(xiàn)。
    • Lock 更靈活(可中斷、超時(shí)、公平鎖等),但需手動(dòng)釋放鎖。
  5. wait/notify 使用注意:
    • 必須在同步塊內(nèi)調(diào)用。
    • 使用 while 循環(huán)檢查條件,防止虛假喚醒。
    • 明確鎖對(duì)象,調(diào)用 obj.wait() 時(shí)必須持有 obj 的鎖。

四、示例代碼

public class SynchronizedExample {
    private final Object lock = new Object();
    private int count = 0;

    // 同步實(shí)例方法
    public synchronized void increment() {
        count++;
    }

    // 同步靜態(tài)方法
    public static synchronized void staticMethod() {
        // ...
    }

    // 同步代碼塊
    public void doSomething() {
        synchronized (lock) {
            // 同步代碼
        }
    }
}

總結(jié)

synchronized 是 Java 中最基本的線程同步機(jī)制,通過(guò) JVM 的 Monitor 和精細(xì)的鎖升級(jí)策略(偏向鎖->輕量級(jí)鎖->重量級(jí)鎖)實(shí)現(xiàn)了在高性能無(wú)競(jìng)爭(zhēng)場(chǎng)景和高強(qiáng)度競(jìng)爭(zhēng)場(chǎng)景下的自適應(yīng)同步。其內(nèi)置的 wait/notify 機(jī)制為線程間協(xié)調(diào)提供了基礎(chǔ)。使用時(shí)需注意鎖的范圍、競(jìng)爭(zhēng)情況以及 wait/notify 的正確用法,以避免性能問(wèn)題和邏輯錯(cuò)誤。對(duì)于更復(fù)雜的場(chǎng)景,可以考慮 java.util.concurrent 包中的高級(jí)并發(fā)工具。

到此這篇關(guān)于java synchronized關(guān)鍵字用法和底層原理舉例詳解的文章就介紹到這了,更多相關(guān)java synchronized關(guān)鍵字用法內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解Java Bellman-Ford算法原理及實(shí)現(xiàn)

    詳解Java Bellman-Ford算法原理及實(shí)現(xiàn)

    Bellman-Ford算法與Dijkstra算法類似,都是以松弛操作作為基礎(chǔ),Bellman-Ford算法是對(duì)所有邊都進(jìn)行松弛操作,本文將詳解Bellman-Ford算法原理及實(shí)現(xiàn),感興趣的可以了解一下
    2022-07-07
  • java向數(shù)據(jù)庫(kù)插入數(shù)據(jù)顯示亂碼的幾種問(wèn)題解決

    java向數(shù)據(jù)庫(kù)插入數(shù)據(jù)顯示亂碼的幾種問(wèn)題解決

    這篇文章主要給大家介紹了關(guān)于java向數(shù)據(jù)庫(kù)插入數(shù)據(jù)顯示亂碼問(wèn)題的解決方案,文章分別羅列了前臺(tái)亂碼的問(wèn)題、前臺(tái)先后臺(tái)插入數(shù)據(jù)后臺(tái)接收到的數(shù)據(jù)是亂碼以及后臺(tái)向數(shù)據(jù)庫(kù)插入數(shù)據(jù)是亂碼等幾種情況,需要的朋友可以參考下
    2021-11-11
  • Intellij IDEA調(diào)試技巧的深入講解

    Intellij IDEA調(diào)試技巧的深入講解

    這篇文章主要給大家介紹了關(guān)于Intellij IDEA調(diào)試技巧的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-08-08
  • Java詳細(xì)講解包的作用以及修飾符的介紹

    Java詳細(xì)講解包的作用以及修飾符的介紹

    本文主要講述的是包的使用和注意事項(xiàng)和四種訪問(wèn)修飾符public,protected,默認(rèn)的,private的訪問(wèn)范圍及實(shí)例,感興趣的朋友一起來(lái)看看
    2022-05-05
  • Intellij IDEA如何去掉@Autowired 注入警告的方法

    Intellij IDEA如何去掉@Autowired 注入警告的方法

    這篇文章主要介紹了Intellij IDEA如何去掉@Autowired 注入警告的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-04-04
  • Java多線程、進(jìn)度條實(shí)現(xiàn)賽馬實(shí)驗(yàn)的示例代碼

    Java多線程、進(jìn)度條實(shí)現(xiàn)賽馬實(shí)驗(yàn)的示例代碼

    這篇文章主要介紹了Java多線程、進(jìn)度條實(shí)現(xiàn)賽馬實(shí)驗(yàn)的示例代碼,代碼簡(jiǎn)單易懂,對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • Java中的靜態(tài)代碼塊使用解讀

    Java中的靜態(tài)代碼塊使用解讀

    本文將深入探討靜態(tài)代碼塊的工作原理、使用場(chǎng)景以及一些最佳實(shí)踐,幫助你更好地理解和應(yīng)用這一特性
    2025-02-02
  • IntelliJ IDEA 2020.3 重大特性(新功能一覽)

    IntelliJ IDEA 2020.3 重大特性(新功能一覽)

    這篇文章主要介紹了IntelliJ IDEA 2020.3 重大特性(新功能一覽),本文通過(guò)圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 【java 多線程】守護(hù)線程與非守護(hù)線程的詳解

    【java 多線程】守護(hù)線程與非守護(hù)線程的詳解

    這篇文章主要介紹了java守護(hù)線程與非守護(hù)線程,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-04-04
  • springboot集成Kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼過(guò)程

    springboot集成Kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼過(guò)程

    這篇文章主要介紹了springboot集成Kaptcha實(shí)現(xiàn)圖片驗(yàn)證碼過(guò)程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06

最新評(píng)論

平泉县| 红桥区| 澄城县| 古浪县| 洞头县| 巴南区| 英吉沙县| 泽普县| 灵宝市| 嘉黎县| 富裕县| 新丰县| 大悟县| 四会市| 淮阳县| 吉安市| 泊头市| 百色市| 兰溪市| 新竹县| 钦州市| 乌审旗| 巴南区| 靖边县| 石河子市| 宜城市| 朝阳市| 日土县| 武强县| 沙田区| 古浪县| 托克托县| 凉山| 马公市| 大冶市| 嘉义市| 嘉峪关市| 和平县| 清涧县| 新乡市| 大荔县|