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

一文帶你徹底剖析Java中Synchronized原理

 更新時(shí)間:2023年05月02日 09:59:35   作者:小小小小明明明明明明明明  
Synchronized是Java中的隱式鎖,它的獲取鎖和釋放鎖都是隱式的,完全交由JVM幫助我們操作,在了解Synchronized關(guān)鍵字之前,首先要學(xué)習(xí)的知識(shí)點(diǎn)就是Java的對(duì)象結(jié)構(gòu),本文介紹的非常詳細(xì),需要的朋友可以參考下

源碼級(jí)別剖析Synchronized

對(duì)象結(jié)構(gòu)

Synchronized是Java中的隱式鎖,它的獲取鎖和釋放鎖都是隱式的,完全交由JVM幫助我們操作,在了解Synchronized關(guān)鍵字之前,首先要學(xué)習(xí)的知識(shí)點(diǎn)就是Java的對(duì)象結(jié)構(gòu),因?yàn)镾ynchronized鎖就是存放在Java對(duì)象中的,Java對(duì)象結(jié)構(gòu)如下圖所示:

可以清晰的看到Java對(duì)象由三部分組成,分別是對(duì)象頭、實(shí)例數(shù)據(jù)、填充數(shù)據(jù),我們的鎖就存放在對(duì)象頭中,接下來(lái)我們將對(duì)對(duì)象結(jié)構(gòu)做一個(gè)簡(jiǎn)單的解析:

  • mark-down:對(duì)象標(biāo)記字段占8個(gè)字節(jié),用于存儲(chǔ)有關(guān)鎖的標(biāo)記位等信息,從圖中可以看出有哈希值、輕量級(jí)鎖的標(biāo)記位、偏向鎖標(biāo)記位等。
  • Klass Pointer:Class對(duì)象的類型指針,它就是指向當(dāng)前對(duì)象屬于哪個(gè)Class類的指針,jdk1.8默認(rèn)開(kāi)啟壓縮指針后占用4個(gè)字節(jié),關(guān)閉壓縮指針后占用8個(gè)字節(jié)。
  • 對(duì)象實(shí)際數(shù)據(jù):這部分內(nèi)容包括對(duì)象的所有成員變量,大小由各個(gè)成員變量決定,比如byte占用1個(gè)字節(jié)、int占用4個(gè)字節(jié)等。
  • 對(duì)其填充:這部分內(nèi)容僅僅只是做到空間補(bǔ)全,就是一個(gè)占位符的作用,因?yàn)镠otSpot虛擬機(jī)的內(nèi)存管理系統(tǒng)要求對(duì)象的起始地址必須是8字節(jié)的整數(shù)倍,因此如果出現(xiàn)對(duì)象實(shí)例沒(méi)有對(duì)齊的話,就需要通過(guò)對(duì)其填充來(lái)補(bǔ)充。

在mark-down鎖類型標(biāo)記中,可以看到總共有五種類型,分別是無(wú)鎖、偏向鎖、輕量級(jí)鎖、重量級(jí)鎖、GC標(biāo)記,所以如果只是使用2比特標(biāo)記是無(wú)法完全被表示出來(lái)的,所以引入了一位偏向鎖標(biāo)記,也就是說(shuō)001為無(wú)鎖、101為偏向鎖。

Monitor 對(duì)象

上面介紹了對(duì)象結(jié)構(gòu),可以看到在Mark-down中會(huì)存儲(chǔ)不同的鎖信息,當(dāng)鎖的狀態(tài)為重量級(jí)鎖(10)時(shí),Mark-down中會(huì)存放一個(gè)指向Monitor對(duì)象的指針,這個(gè)Monitor對(duì)象也稱為監(jiān)視器鎖。

synchronized的運(yùn)行機(jī)制,就是JVM檢測(cè)到共享對(duì)象存在不同的競(jìng)爭(zhēng)情況的時(shí)候,會(huì)自動(dòng)切換到適合的鎖實(shí)現(xiàn),這種切換就是鎖的升級(jí)、降級(jí)。(很多地方都說(shuō)鎖只能升級(jí),不能降級(jí),其實(shí)這種說(shuō)法是錯(cuò)誤的,在《Java并發(fā)編程的藝術(shù)》書(shū)中說(shuō)到,對(duì)于偏向鎖來(lái)說(shuō),它可以進(jìn)行降級(jí)到無(wú)鎖狀態(tài),也叫做偏向鎖的撤銷)。

那么現(xiàn)在就存在著三種不同的Monitor實(shí)現(xiàn),分別是偏向鎖、輕量級(jí)鎖和重量級(jí)鎖。如果一個(gè)Monitor被一個(gè)線程持有的時(shí)候,就說(shuō)明這個(gè)線程拿到了鎖。

Java中的Monitor是基于C++的ObjectMonitor實(shí)現(xiàn)的,它的主要成員包括:

  • _owner:指向持有ObjectMonitor對(duì)象的線程
  • _WaitSet:存放處于wait狀態(tài)的線程隊(duì)列,即調(diào)用wait()方法的線程
  • _EntryList:存放處于等待鎖Block狀態(tài)的線程隊(duì)列
  • _count:約為_(kāi)WaitSet+_EntryList的節(jié)點(diǎn)數(shù)之和
  • _cxq:多個(gè)線程爭(zhēng)搶鎖,會(huì)先存入這個(gè)單向鏈表
  • _recursions:記錄重入次數(shù)
  • _object:存儲(chǔ)的Monitor對(duì)象

獲取Monitor對(duì)象的線程進(jìn)入_owner區(qū)的時(shí)候,_count+1,如果線程調(diào)用了wait()方法,那么會(huì)釋放Monitor對(duì)象(釋放鎖),_owner恢復(fù)為空同時(shí)_count-1。此時(shí)該線程進(jìn)入_WaitSet隊(duì)列中,等待被喚醒。

從上述的描述可以看出,synchronized關(guān)鍵字獲取鎖的關(guān)鍵在于每個(gè)對(duì)象的對(duì)象頭中,這也就能解釋了為什么synchronized()括號(hào)里存放任何對(duì)象都能獲得鎖的特征。

Synchronized特征

原子性

原子性,就是說(shuō)一個(gè)操作要么完成,要么不完成,不存在完成一半的情況,也就是說(shuō)這個(gè)操作是不可中斷的。

synchronized可以保證同一時(shí)間內(nèi)只有一個(gè)線程拿到鎖,進(jìn)入到代碼塊去執(zhí)行代碼,這樣說(shuō)如果不能理解,那么就想象下面的一個(gè)場(chǎng)景,有一個(gè)廁所只有一個(gè)坑位,并且?guī)€上鎖了,就是為了防止多人一起上廁所的不文明現(xiàn)象,每個(gè)人上廁所都必須要去廁所管理員處繳費(fèi),繳費(fèi)后才能拿到鎖再去上廁所,上完廁所再把要是還給廁所管理員,synchronized就是廁所管理員,保證一次只能有一個(gè)人拿到鎖,并且每個(gè)人用完廁所之后都必須要?dú)w還鑰匙。

接下來(lái)看到下面一個(gè)同步加方法:

public static void add() {
    synchronized (Demo.class) {
        counter++;
    }
}

將其進(jìn)行反編譯后查看代碼:

javap -v -p Demo

public static void add();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC , ACC_SYNCHRONIZED
    Code:
      stack=2, locals=2, args_size=0
         0: ldc           #12                 // class
         2: dup
         3: astore_0
         4: monitorenter
         5: getstatic     #10                 // Field counter:I
         8: iconst_1
         9: iadd
        10: putstatic     #10                 // Field counter:I
        13: aload_0
        14: monitorexit
        15: goto          23
        18: astore_1
        19: aload_0
        20: monitorexit
        21: aload_1
        22: athrow
        23: return
      Exception table:

可以看到有兩個(gè)指令明顯和monitor有關(guān):

  • monitorenter:在判斷擁有同步標(biāo)識(shí) ACC_SYNCHRONIZED 搶先進(jìn)入此方法的線程會(huì)優(yōu)先擁有 Monitor 的 owner ,此時(shí)計(jì)數(shù)器 +1
  • monitorexit:當(dāng)執(zhí)行完退出后,計(jì)數(shù)器 -1,歸 0 后被其他進(jìn)入的線程獲得

可見(jiàn)性

可見(jiàn)性指的是當(dāng)多個(gè)線程訪問(wèn)同一個(gè)變量時(shí),一個(gè)線程修改了這個(gè)變量的值,其他的線程能夠立馬感知,能看到修改后的值。(線程的可見(jiàn)性和一個(gè)叫JMM的東西息息相關(guān),后面會(huì)寫一篇關(guān)于可見(jiàn)性結(jié)合volatile關(guān)鍵字的文章)

而Synchronized擁有可見(jiàn)性,因?yàn)樗渔i和釋放鎖都有如下語(yǔ)義:

  • 線程加鎖前,必須清空工作內(nèi)存中共享變量的值,從而從主內(nèi)存中讀取最新的共享變量的值。
  • 線程釋放鎖時(shí),必須把共享變量的值刷新到主內(nèi)存中。
  • synchronized的可見(jiàn)性依賴于操作系統(tǒng)內(nèi)核互斥鎖實(shí)現(xiàn),相當(dāng)于JVM中的lock,unlock,退出代碼塊時(shí)需要刷新共享變量到主內(nèi)存中,這一點(diǎn)和volatile關(guān)鍵字不一樣,volatile關(guān)鍵字的可見(jiàn)性是依賴于內(nèi)存屏障(也叫內(nèi)存柵欄)來(lái)實(shí)現(xiàn)的。

有序性

as-if-serial,就是保證不管編譯器和處理器為了性能優(yōu)化怎樣進(jìn)行指令重排序,都需要保證單線程下的運(yùn)行結(jié)果的正確性。也就是常說(shuō)的:如果在本線程內(nèi)觀察,所有的操作都是有序的,如果在一個(gè)線程觀察另一個(gè)線程,所有的操作都是無(wú)序的。

注意,這里的有序性和volatile是不一樣的,它并不是volatile的防止指令重排序。

可重入鎖

可重入鎖的概念很簡(jiǎn)單,就是一個(gè)線程可以多次獲取自己持有的對(duì)象鎖,這種鎖就是可重入鎖,同樣的釋放鎖也就需要釋放相同數(shù)量的鎖。synchronized鎖對(duì)象中就有一個(gè)計(jì)數(shù)器,用于存放獲取鎖的次數(shù),也就是重入次數(shù)。

鎖升級(jí)的過(guò)程

synchronized 鎖有四種交替升級(jí)的狀態(tài):無(wú)鎖、偏向鎖、輕量級(jí)鎖和重量級(jí),這幾個(gè)狀態(tài)隨著競(jìng)爭(zhēng)情況逐漸升級(jí),后續(xù)會(huì)補(bǔ)上一張完整的鎖升級(jí)圖。

以上就是一文帶你徹底剖析Java中Synchronized原理的詳細(xì)內(nèi)容,更多關(guān)于Java Synchronized的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Springboot+Hutool自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏

    Springboot+Hutool自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏

    我們?cè)陧?xiàng)目中會(huì)處理敏感數(shù)據(jù)時(shí),通常需要對(duì)這些數(shù)據(jù)進(jìn)行脫敏,本文主要使用了Springboot整合Hutool來(lái)自定義注解實(shí)現(xiàn)數(shù)據(jù)脫敏,感興趣的可以理解下
    2023-10-10
  • MyEclipse2018中安裝Mybatis generator插件的實(shí)現(xiàn)步驟

    MyEclipse2018中安裝Mybatis generator插件的實(shí)現(xiàn)步驟

    這篇文章主要介紹了MyEclipse2018中安裝Mybatis generator插件的實(shí)現(xiàn)步驟,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-02-02
  • 學(xué)習(xí)Java內(nèi)存模型JMM心得

    學(xué)習(xí)Java內(nèi)存模型JMM心得

    這篇文章主要介紹了學(xué)習(xí)Java內(nèi)存模型JMM的心得以及對(duì)其原理做了深入的介紹,有興趣的朋友學(xué)習(xí)下吧。
    2017-12-12
  • SpringBoot整合log4j日志與HashMap的底層原理解析

    SpringBoot整合log4j日志與HashMap的底層原理解析

    這篇文章主要介紹了SpringBoot整合log4j日志與HashMap的底層原理,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-01-01
  • Hadoop的安裝與環(huán)境搭建教程圖解

    Hadoop的安裝與環(huán)境搭建教程圖解

    這篇文章主要介紹了Hadoop的安裝與環(huán)境搭建教程圖解,本文圖文并茂給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-06-06
  • SWT(JFace)體驗(yàn)之ApplicationWindow

    SWT(JFace)體驗(yàn)之ApplicationWindow

    SWT(JFace)體驗(yàn)之ApplicationWindow
    2009-06-06
  • struts2 中文亂碼的解決辦法分享

    struts2 中文亂碼的解決辦法分享

    這篇文章主要介紹了struts2 中文亂碼的解決辦法,需要的朋友可以參考下
    2014-02-02
  • Java中遍歷集合的并發(fā)修改異常解決方案實(shí)例代碼

    Java中遍歷集合的并發(fā)修改異常解決方案實(shí)例代碼

    當(dāng)你遍歷集合的同時(shí),又往集合中添加或者刪除元素,就可能報(bào)并發(fā)修改異常,下面這篇文章主要給大家介紹了關(guān)于Java中遍歷集合的并發(fā)修改異常解決方案的相關(guān)資料,需要的朋友可以參考下
    2022-12-12
  • Spring Bean常用的的裝配方式詳解

    Spring Bean常用的的裝配方式詳解

    這篇文章主要介紹了Spring Bean常用的的裝配方式詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-07-07
  • springboot整合spring-data-redis遇到的坑

    springboot整合spring-data-redis遇到的坑

    使用springboot整合redis,使用默認(rèn)的序列化配置,然后使用redis-client去查詢時(shí)查詢不到相應(yīng)的key.問(wèn)題出在哪,怎么解決呢?下面小編給大家?guī)?lái)了springboot整合spring-data-redis遇到的坑,需要的的朋友參考下吧
    2017-04-04

最新評(píng)論

新津县| 六盘水市| 上栗县| 北辰区| 太谷县| 诸城市| 水富县| 临澧县| 页游| 新源县| 高淳县| 霸州市| 离岛区| 报价| 鄂尔多斯市| 客服| 治多县| 灵璧县| 闵行区| 廊坊市| 平邑县| 图片| 德安县| 当阳市| 鲁山县| 西昌市| 化州市| 涞水县| 巍山| 淮阳县| 获嘉县| 临朐县| 武川县| 巴马| 随州市| 万载县| 麻阳| 都匀市| 商城县| 湖口县| 长海县|