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

Java?ynchronized重量級鎖的核心原理詳解

 更新時間:2022年03月01日 16:45:34   作者:小小茶花女  
這篇文章主要為大家詳細介紹了Java?ynchronized重量級鎖的核心原理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助

在JVM中,每個對象都關(guān)聯(lián)一個監(jiān)視器,這里的對象包含Object實例和Class實例。監(jiān)視器是一個同步工具,相當于一個許可證,拿到許可證的線程即可進入臨界區(qū)進行操作,沒有拿到則需要阻塞等待。重量級鎖通過監(jiān)視器的方式保障了任何時間只允許一個線程通過受到監(jiān)視器保護的臨界區(qū)代碼。

1. monitor原理

jvm中每個對象都會有一個監(jiān)視器Monitor,監(jiān)視器和對象一起創(chuàng)建、銷毀。監(jiān)視器相當于一個用來監(jiān)視這些線程進入的特殊房間,其義務(wù)是保證(同一時間)只有一個線程可以訪問被保護的臨界區(qū)代碼塊。

每一個鎖都對應(yīng)一個monitor對象,在HotSpot虛擬機中它是由ObjectMonitor實現(xiàn)的(C++實現(xiàn))

//部分屬性
ObjectMonitor() {
    _count        = 0;     //鎖計數(shù)器
    _owner        = NULL;
    _WaitSet      = NULL;  //處于wait狀態(tài)的線程,會被加入到_WaitSet
    _EntryList    = NULL ; //處于等待鎖block狀態(tài)的線程,會被加入到該列表
  }

本質(zhì)上,監(jiān)視器是一種同步工具,也可以說是一種同步機制,主要特點是:

  • 同步。監(jiān)視器所保護的臨界區(qū)代碼是互斥地執(zhí)行的。一個監(jiān)視器是一個運行許可,任一線程進入臨界區(qū)代碼都需要獲得這個許可,離開時把許可歸還。
  • 協(xié)作。監(jiān)視器提供Signal機制,允許正持有許可的線程暫時放棄許可進入阻塞等待狀態(tài),等待其他線程發(fā)送Signal去喚醒;其他擁有許可的線程可以發(fā)送Signal,喚醒正在阻塞等待的線程,讓它可以重新獲得許可并啟動執(zhí)行。

在這里插入圖片描述

每個java 對象都可以關(guān)聯(lián)一個 Monitor 對象,如果使用 synchronized 給對象上鎖(重量級)之后,該對象頭的mark word中就被設(shè)置指向 Monitor 對象的指針。

(1) 如果使用 synchronized 給obj對象上鎖,obj對象的markword就會指向一個monitor鎖對象;

(2) 剛開始 Monitor 中 Owner 為 null ;

(3) 當Thread-2線程持有monitor對象后,就會把monitor中的owner變量設(shè)置為當前線程Thread-2;

(4) 當Thread-3線程想要執(zhí)行臨界區(qū)的代碼時,要判斷monitor對象的屬性O(shè)wner是否為null,如果為null,Thread-3線程就持有了對象鎖,如果不為null,Thread-3線程就會放入monitor的EntryList阻塞隊列中,處于阻塞狀態(tài)Blocked。

(5) 在 Thread-2 上鎖的過程中,如果Thread-4,Thread-5 也來執(zhí)行 synchronized(obj),也會進入EntryList BLOCKED ;

(6) Thread-2 執(zhí)行完同步代碼塊的內(nèi)容,就會釋放鎖,將owner變量置為null,并喚醒EntryList 中阻塞的線程來競爭鎖,競爭時是非公平的 ;

(7) 圖中 WaitSet 中的 Thread-0,Thread-1 是之前獲得過鎖,但條件不滿足進入 WAITING 狀態(tài)的線程,后面講 wait-notify 時會分析

2. snychronized同步代碼塊原理

public class TestSynchronized {
    static final Object obj = new Object();
    static int i=0;
    public static void main(String[] args) {
        synchronized (obj){
            i++;
        }
    }
}

將上面的代碼反編譯為字節(jié)碼文件:

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=3, args_size=1
         0: getstatic     #2         // 獲取obj對象
         3: dup
         4: astore_1
         5: monitorenter		//將obj對象的markword置為monitor指針
         6: getstatic     #3                  
         9: iconst_1
        10: iadd
        11: putstatic     #3                  
        14: aload_1
        15: monitorexit			//同步代碼塊正常執(zhí)行時,將obj對象的markword重置,喚醒EntryList
        16: goto          24
        19: astore_2
        20: aload_1
        21: monitorexit			//同步代碼塊出現(xiàn)異常時,將obj對象的markword重置,喚醒EntryList
        22: aload_2
        23: athrow
        24: return
      Exception table:
         from    to  target type
             6    16    19   any  //監(jiān)測6-16行jvm指令,如果出現(xiàn)異常就會到第19行
            19    22    19   any

這兩條指令的作用,我們直接參考JVM規(guī)范中描述:

monitorenter 指令:

每個對象有一個監(jiān)視器鎖(monitor)。當monitor被占用時就會處于鎖定狀態(tài),線程執(zhí)行monitorenter指令時嘗試獲取monitor的所有權(quán),過程如下:

(1) 如果monitor的進入數(shù)為0,則該線程進入monitor,然后將進入數(shù)設(shè)置為1,該線程即為monitor的所有者

(2) 如果線程已經(jīng)占有該monitor,只是重新進入,則進入monitor的進入數(shù)加1.

(3) 如果其他線程已經(jīng)占用了monitor,則該線程進入阻塞狀態(tài),直到monitor的進入數(shù)為0,再重新嘗試獲取monitor的所有權(quán)。

monitorexit指令:

執(zhí)行monitorexit的線程必須是持有obj鎖對象的線程

指令執(zhí)行時,monitor的進入數(shù)減1,如果減1后進入數(shù)為0,那線程釋放monitor,不再是這個monitor的所有者。其他被這個monitor阻塞的線程可以嘗試去獲取這個 monitor 的所有權(quán)。

Synchronized的語義底層是通過一個monitor的對象來完成,其實wait/notify等方法也依賴于monitor對象,這就是為什么只有在同步的塊或者方法中才能調(diào)用wait/notify等方法,否則會拋出IllegalMonitorStateException的異常的原因。

3. synchronized同步方法原理

public class TestSynchronized {
    static int i=0;
    public synchronized  void add(){
        i++;
    }
}

對應(yīng)的字節(jié)碼指令:

 public synchronized void add();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=2, locals=1, args_size=1
         0: getstatic     #2                  // Field i:I
         3: iconst_1
         4: iadd
         5: putstatic     #2                  // Field i:I
         8: return

從反編譯的結(jié)果來看,方法的同步并沒有通過指令monitorentermonitorexit來完成不過相對于普通方法,其常量池中多了ACC_SYNCHRONIZED標示符。JVM就是根據(jù)該標示符來實現(xiàn)方法的同步的:當方法調(diào)用時,調(diào)用指令將會檢查方法的 ACC_SYNCHRONIZED 訪問標志是否被設(shè)置,如果設(shè)置了,執(zhí)行線程將先獲取monitor,獲取成功之后才能執(zhí)行方法體,方法執(zhí)行完后再釋放monitor。在方法執(zhí)行期間,其他任何線程都無法再獲得同一個monitor對象。 其實本質(zhì)上沒有區(qū)別,只是方法的同步是一種隱式的方式來實現(xiàn),無需通過字節(jié)碼來完成。

4. 重量級鎖的開銷

處于ContentionList、EntryListWaitSet中的線程都處于阻塞狀態(tài),線程的阻塞或者喚醒都需要操作系統(tǒng)來幫忙,Linux內(nèi)核下采用pthread_mutex_lock系統(tǒng)調(diào)用實現(xiàn),進程需要從用戶態(tài)切換到內(nèi)核態(tài)。

用戶態(tài)是應(yīng)用程序運行的空間,為了能訪問到內(nèi)核管理的資源(例如CPU、內(nèi)存、I/O),可以通過內(nèi)核態(tài)所提供的訪問接口實現(xiàn),這些接口就叫系統(tǒng)調(diào)用。

pthread_mutex_lock系統(tǒng)調(diào)用是內(nèi)核態(tài)為用戶態(tài)進程提供的Linux內(nèi)核態(tài)下互斥鎖的訪問機制,所以使用pthread_mutex_lock系統(tǒng)調(diào)用時,進程需要從用戶態(tài)切換到內(nèi)核態(tài),而這種切換是需要消耗很多時間的,有可能比用戶執(zhí)行代碼的時間還要長。

由于JVM輕量級鎖使用CAS進行自旋搶鎖,這些CAS操作都處于用戶態(tài)下,進程不存在用戶態(tài)和內(nèi)核態(tài)之間的運行切換,因此JVM輕量級鎖開銷較小。而JVM重量級鎖使用了Linux內(nèi)核態(tài)下的互斥鎖,這是重量級鎖開銷很大的原因。

總結(jié)

本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容! 

相關(guān)文章

  • 深入理解Java8新特性之Stream API的創(chuàng)建方式和中間操作步驟

    深入理解Java8新特性之Stream API的創(chuàng)建方式和中間操作步驟

    Stream是Java8的一大亮點,是對容器對象功能的增強,它專注于對容器對象進行各種非常便利、高效的 聚合操作(aggregate operation)或者大批量數(shù)據(jù)操作。Stream API借助于同樣新出現(xiàn)的Lambda表達式,極大的提高編程效率和程序可讀性,感興趣的朋友快來看看吧
    2021-11-11
  • Java多線程模擬電影售票過程

    Java多線程模擬電影售票過程

    這篇文章主要為大家詳細介紹了Java多線程模擬電影售票過程,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-11-11
  • IntelliJ IDEA(或者JetBrains PyCharm)中彈出

    IntelliJ IDEA(或者JetBrains PyCharm)中彈出"IntelliJ IDEA License

    今天小編就為大家分享一篇關(guān)于IntelliJ IDEA(或者JetBrains PyCharm)中彈出"IntelliJ IDEA License Activation"的解決辦法,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-10-10
  • SpringMVC訪問靜態(tài)資源的三種方式小結(jié)

    SpringMVC訪問靜態(tài)資源的三種方式小結(jié)

    這篇文章主要介紹了SpringMVC訪問靜態(tài)資源的三種方式小結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-02-02
  • 簡單了解Java關(guān)鍵字throw和throws的區(qū)別

    簡單了解Java關(guān)鍵字throw和throws的區(qū)別

    這篇文章主要介紹了簡單了解Java關(guān)鍵字throw和throws的區(qū)別,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • java開發(fā)ShardingSphere的路由引擎類型示例詳解

    java開發(fā)ShardingSphere的路由引擎類型示例詳解

    這篇文章主要為大家介紹了java開發(fā)ShardingSphere的路由引擎類型示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-08-08
  • Java垃圾回收機制的示例詳解

    Java垃圾回收機制的示例詳解

    本文主要圍繞著Java垃圾回收當中的哪些內(nèi)存需要回收?什么時候回收?如何回收?進行了詳細講解,感興趣的小伙伴可以學(xué)習(xí)一下
    2022-04-04
  • Springboot實現(xiàn)WebMvcConfigurer接口定制mvc配置詳解

    Springboot實現(xiàn)WebMvcConfigurer接口定制mvc配置詳解

    這篇文章主要介紹了Springboot實現(xiàn)WebMvcConfigurer接口定制mvc配置詳解,spring?boot拋棄了傳統(tǒng)xml配置文件,通過配置類(標注@Configuration的類,@Configuration配置類相當于一個xml配置文件)以JavaBean形式進行相關(guān)配置,需要的朋友可以參考下
    2023-09-09
  • Spring @Retryable注解輕松搞定循環(huán)重試功能

    Spring @Retryable注解輕松搞定循環(huán)重試功能

    spring系列的spring-retry是另一個實用程序模塊,可以幫助我們以標準方式處理任何特定操作的重試。在spring-retry中,所有配置都是基于簡單注釋的。本文主要介紹了Spring@Retryable注解如何輕松搞定循環(huán)重試功能,有需要的朋友可以參考一下
    2023-04-04
  • 解決idea?中?SpringBoot?點擊運行沒反應(yīng)按鈕成灰色的問題

    解決idea?中?SpringBoot?點擊運行沒反應(yīng)按鈕成灰色的問題

    在使用 Spring Boot 開發(fā)項目時,可能會遇到一個問題:點擊運行按鈕后,控制臺沒有任何輸出,項目界面也沒有顯示,這種情況可能是由多種原因?qū)е碌?,本文將介紹一些常見的解決方法,需要的朋友可以參考下
    2023-08-08

最新評論

厦门市| 长沙县| 遵义县| 武穴市| 长汀县| 汉寿县| 乡城县| 郯城县| 荥阳市| 青神县| 平武县| 丹寨县| 土默特左旗| 黎川县| 九寨沟县| 文昌市| 精河县| 建德市| 疏勒县| 当雄县| 海门市| 扎囊县| 广丰县| 德州市| 盐池县| 丰镇市| 兴宁市| 多伦县| 奉节县| 昭苏县| 资源县| 大厂| 仙游县| 雷波县| 化隆| 榆树市| 化德县| 调兵山市| 丽水市| 北宁市| 沧源|