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

synchronized背后的monitor鎖實現(xiàn)詳解

 更新時間:2022年09月07日 08:51:23   作者:會飛的湯姆貓  
這篇文章主要為大家介紹了synchronized背后的monitor鎖實現(xiàn)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

獲取和釋放 monitor 鎖的時機

本文我們研究下 synchronized 背后的 monitor 鎖。

我們都知道,最簡單的同步方式就是利用 synchronized 關(guān)鍵字來修飾代碼塊或者修飾一個方法,那么這部分被保護的代碼,在同一時刻就最多只有一個線程可以運行,而 synchronized 的背后正是利用 monitor 鎖實現(xiàn)的。所以首先我們來看下獲取和釋放 monitor 鎖的時機,每個 Java 對象都可以用作一個實現(xiàn)同步的鎖,這個鎖也被稱為內(nèi)置鎖或 monitor 鎖,獲得 monitor 鎖的唯一途徑就是進入由這個鎖保護的同步代碼塊或同步方法,線程在進入被 synchronized 保護的代碼塊之前,會自動獲取鎖,并且無論是正常路徑退出,還是通過拋出異常退出,在退出的時候都會自動釋放鎖。

我們首先來看一個 synchronized 修飾方法的代碼的例子:

public synchronized void method() {
    method body
}

我們看到 method() 方法是被 synchronized 修飾的,為了方便理解其背后的原理,我們把上面這段代碼改寫為下面這種等價形式的偽代碼。

public void method() {
    this.intrinsicLock.lock();
    try{
        method body
    }
    finally {
        this.intrinsicLock.unlock();
    }
}

在這種寫法中,進入 method 方法后,立刻添加內(nèi)置鎖,并且用 try 代碼塊把方法保護起來,最后用 finally 釋放這把鎖,這里的 intrinsicLock 就是 monitor 鎖。經(jīng)過這樣的偽代碼展開之后,相信你對 synchronized 的理解就更加清晰了。

用 javap 命令查看反匯編的結(jié)果

JVM 實現(xiàn) synchronized 方法和 synchronized 代碼塊的細節(jié)是不一樣的,下面我們就分別來看一下兩者的實現(xiàn)。

同步代碼塊

首先我們來看下同步代碼塊的實現(xiàn),如代碼所示。

public class SynTest {
    public void synBlock() {
        synchronized (this) {
            System.out.println("lagou");
        }
    }
}

在 SynTest 類中的 synBlock 方法,包含一個同步代碼塊,synchronized 代碼塊中有一行代碼打印了 lagou 字符串,下面我們來通過命令看下 synchronized 關(guān)鍵字到底做了什么事情:首先用 cd 命令切換到 SynTest.java 類所在的路徑,然后執(zhí)行 javac SynTest.java,于是就會產(chǎn)生一個名為 SynTest.class 的字節(jié)碼文件,然后我們執(zhí)行 javap -verbose SynTest.class,就可以看到對應的反匯編內(nèi)容。

關(guān)鍵信息如下:

  public void synBlock();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter
         4: getstatic     #2                  // Field java/lang/System.out:Ljava/io/PrintStream;
         7: ldc           #3                      // String lagou
         9: invokevirtual #4               // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        12: aload_1
        13: monitorexit
        14: goto          22
        17: astore_2
        18: aload_1
        19: monitorexit
        20: aload_2
        21: athrow
        22: return

從里面可以看出,synchronized 代碼塊實際上多了 monitorenter 和 monitorexit 指令,標紅的第3、13、19行指令分別對應的是 monitorenter 和 monitorexit。這里有一個 monitorenter,卻有兩個 monitorexit 指令的原因是,JVM 要保證每個 monitorenter 必須有與之對應的 monitorexit,monitorenter 指令被插入到同步代碼塊的開始位置,而 monitorexit 需要插入到方法正常結(jié)束處和異常處兩個地方,這樣就可以保證拋異常的情況下也能釋放鎖

可以把執(zhí)行 monitorenter 理解為加鎖,執(zhí)行 monitorexit 理解為釋放鎖,每個對象維護著一個記錄著被鎖次數(shù)的計數(shù)器。未被鎖定的對象的該計數(shù)器為 0,我們來具體看一下 monitorenter 和 monitorexit 的含義:

  • monitorenter

執(zhí)行 monitorenter 的線程嘗試獲得 monitor 的所有權(quán),會發(fā)生以下這三種情況之一:

a. 如果該 monitor 的計數(shù)為 0,則線程獲得該 monitor 并將其計數(shù)設(shè)置為 1。然后,該線程就是這個 monitor 的所有者。

b. 如果線程已經(jīng)擁有了這個 monitor ,則它將重新進入,并且累加計數(shù)。

c. 如果其他線程已經(jīng)擁有了這個 monitor,那個這個線程就會被阻塞,直到這個 monitor 的計數(shù)變成為 0,代表這個 monitor 已經(jīng)被釋放了,于是當前這個線程就會再次嘗試獲取這個 monitor。

  • monitorexit monitorexit 的作用是將 monitor 的計數(shù)器減 1,直到減為 0 為止。代表這個 monitor 已經(jīng)被釋放了,已經(jīng)沒有任何線程擁有它了,也就代表著解鎖,所以,其他正在等待這個 monitor 的線程,此時便可以再次嘗試獲取這個 monitor 的所有權(quán)。

同步方法

從上面可以看出,同步代碼塊是使用 monitorenter 和 monitorexit 指令實現(xiàn)的。而對于 synchronized 方法,并不是依靠 monitorenter 和 monitorexit 指令實現(xiàn)的,被 javap 反匯編后可以看到,synchronized 方法和普通方法大部分是一樣的,不同在于,這個方法會有一個叫作 ACC_SYNCHRONIZED 的 flag 修飾符,來表明它是同步方法。

同步方法的代碼如下所示。

public synchronized void synMethod() {
}

對應的反匯編指令如下所示。

  public synchronized void synMethod();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=0, locals=1, args_size=1
         0: return
      LineNumberTable:
        line 16: 0

可以看出,被 synchronized 修飾的方法會有一個 ACC_SYNCHRONIZED 標志。當某個線程要訪問某個方法的時候,會首先檢查方法是否有 ACC_SYNCHRONIZED 標志,如果有則需要先獲得 monitor 鎖,然后才能開始執(zhí)行方法,方法執(zhí)行之后再釋放 monitor 鎖。其他方面, synchronized 方法和剛才的 synchronized 代碼塊是很類似的,例如這時如果其他線程來請求執(zhí)行方法,也會因為無法獲得 monitor 鎖而被阻塞。

好了,本文的內(nèi)容就全部講完了,我們講解了獲取和釋放 monitor 的時機,以及被 synchronized 修飾的等價代碼,然后我們還利用 javac 和 javap 命令查看了 synchronized 代碼塊以及 synchronized 方法所對應的的反匯編指令,其中同步代碼塊是利用 monitorenter 和 monitorexit 指令實現(xiàn)的,而同步方法則是利用 flags 實現(xiàn)的。

更多關(guān)于synchronized monitor鎖的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • 使用java為pdf添加書簽的方法(pdf書簽制作)

    使用java為pdf添加書簽的方法(pdf書簽制作)

    下載一些pdf格式的電子書沒有書簽,用JAVA寫了一個小工具,將特定格式的文本解析成為書簽,然后保存到pdf格式中
    2014-02-02
  • 詳解Jmeter線程組的設(shè)置方法

    詳解Jmeter線程組的設(shè)置方法

    本文主要介紹了Jmeter線程組的設(shè)置方法,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2021-11-11
  • JAVA實現(xiàn)打印ascii碼表代碼

    JAVA實現(xiàn)打印ascii碼表代碼

    這篇文章主要介紹了JAVA實現(xiàn)打印ascii碼表代碼,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • Java常見的數(shù)據(jù)結(jié)構(gòu)之棧和隊列詳解

    Java常見的數(shù)據(jù)結(jié)構(gòu)之棧和隊列詳解

    這篇文章主要介紹了Java常見的數(shù)據(jù)結(jié)構(gòu)之棧和隊列詳解,棧(Stack) 是一種基本的數(shù)據(jù)結(jié)構(gòu),具有后進先出(LIFO)的特性,類似于現(xiàn)實生活中的一疊盤子,棧用于存儲一組元素,但只允許在棧頂進行插入(入棧)和刪除(出棧)操作,需要的朋友可以參考下
    2023-10-10
  • Spring Boot 發(fā)送郵件功能案例分析

    Spring Boot 發(fā)送郵件功能案例分析

    這篇文章主要介紹了 Spring Boot 發(fā)送郵件功能,本文通過代碼結(jié)合案例分析給大家介紹的非常詳細,需要的朋友可以參考下
    2017-11-11
  • Java利用opencv實現(xiàn)用字符展示視頻或圖片的方法

    Java利用opencv實現(xiàn)用字符展示視頻或圖片的方法

    這篇文章主要介紹了Java利用opencv實現(xiàn)用字符展示視頻或圖片的方法,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-12-12
  • java中利用Dom4j解析和生成XML文檔

    java中利用Dom4j解析和生成XML文檔

    本篇文章主要介紹了java中利用Dom4j解析和生成XML文檔,dom4j是一套非常優(yōu)秀的Java開源api,主要用于讀寫xml文檔,具有性能優(yōu)異、功能強大、和非常方便使用的特點。有興趣的可以了解一下。
    2016-11-11
  • Java?設(shè)計模式以虹貓藍兔的故事講解原型模式

    Java?設(shè)計模式以虹貓藍兔的故事講解原型模式

    原型模式是用于創(chuàng)建重復的對象,同時又能保證性能。這種類型的設(shè)計模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對象的最佳方式,今天通過本文給大家介紹下Java 原型設(shè)計模式,感興趣的朋友一起看看吧
    2022-04-04
  • 詳解在Java程序中運用Redis緩存對象的方法

    詳解在Java程序中運用Redis緩存對象的方法

    這篇文章主要介紹了在Java程序中運用Redis緩存對象的方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-03-03
  • Spring boot熱部署devtools過程解析

    Spring boot熱部署devtools過程解析

    這篇文章主要介紹了Spring boot熱部署devtools過程解析,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-07-07

最新評論

托克逊县| 孟州市| 遂溪县| 辽宁省| 舟曲县| 长海县| 河南省| 屏南县| 蒙山县| 恭城| 桐乡市| 库伦旗| 左云县| 金堂县| 宣恩县| 朝阳市| 手游| 江华| 张家界市| 巴中市| 舞钢市| 达拉特旗| 怀集县| 扶绥县| 镇宁| 淮南市| 左贡县| 古田县| 山丹县| 阿荣旗| 禹城市| 西和县| 凉城县| 忻城县| 区。| 连江县| 洛南县| 永嘉县| 吴川市| 农安县| 南漳县|