欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解JVM系列之對(duì)象的鎖狀態(tài)和同步

 更新時(shí)間:2021年06月02日 15:15:49   作者:flydean  
鎖和同步是java多線程編程中非常常見的使用場(chǎng)景。為了鎖定多線程共享的對(duì)象,Java需要提供一定的機(jī)制來實(shí)現(xiàn)共享對(duì)象的鎖定。當(dāng)?shù)诙€(gè)線程進(jìn)入同一個(gè)區(qū)域的時(shí)候,必須等待第一個(gè)線程解鎖該對(duì)象。JVM是怎么做到的呢?快來一起看看吧。

java對(duì)象頭

Java的鎖狀態(tài)其實(shí)可以分為三種,分別是偏向鎖,輕量級(jí)鎖和重量級(jí)鎖。

在Java HotSpot VM中,每個(gè)對(duì)象前面都有一個(gè)class指針和一個(gè)Mark Word。 Mark Word存儲(chǔ)了哈希值以及分代年齡和標(biāo)記位等,通過這些值的變化,JVM可以實(shí)現(xiàn)對(duì)java對(duì)象的不同程度的鎖定。

還記得我們之前分享java對(duì)象的那張圖嗎?

javaObject對(duì)象的對(duì)象頭大小根據(jù)你使用的是32位還是64位的虛擬機(jī)的不同,稍有變化。這里我們使用的是64位的虛擬機(jī)為例。

Object的對(duì)象頭,分為兩部分,第一部分是Mark Word,用來存儲(chǔ)對(duì)象的運(yùn)行時(shí)數(shù)據(jù)比如:hashcode,GC分代年齡,鎖狀態(tài),持有鎖信息,偏向鎖的thread ID等等。

在64位的虛擬機(jī)中,Mark Word是64bits,如果是在32位的虛擬機(jī)中Mark Word是32bits。

第二部分就是Klass Word,Klass Word是一個(gè)類型指針,指向class的元數(shù)據(jù),JVM通過Klass Word來判斷該對(duì)象是哪個(gè)class的實(shí)例。

我們可以看到對(duì)象頭中的Mark Word根據(jù)狀態(tài)的不同,存儲(chǔ)的是不同的內(nèi)容。

其中鎖標(biāo)記的值分別是:無鎖=001,偏向鎖=101,輕量級(jí)鎖=000,重量級(jí)鎖=010。

java中鎖狀態(tài)的變化

為什么java中的鎖有三種狀態(tài)呢?其本質(zhì)原因是為了提升鎖的效率,因?yàn)椴煌闆r下,鎖的力度是不一樣的。

通過設(shè)置不同的鎖的狀態(tài),從而可以不同的情況用不同的處理方式。

下圖是java中的鎖狀態(tài)的變化圖:

上面的圖基本上列出了java中鎖狀態(tài)的整個(gè)生命周期。接下來我們一個(gè)一個(gè)的講解。

偏向鎖biased locking

一般來說,一個(gè)對(duì)象被一個(gè)線程獲得鎖之后,很少發(fā)生線程切換的情況。也就是說大部分情況下,一個(gè)對(duì)象只是被一個(gè)對(duì)象鎖定的。

那么這個(gè)時(shí)候我們可以通過設(shè)置Mark word的一定結(jié)構(gòu),減少使用CAS來更新對(duì)象頭的頻率。

為了實(shí)現(xiàn)這樣的目標(biāo),我們看下偏向鎖的Mark word的結(jié)構(gòu):

當(dāng)偏向線程第一次進(jìn)入同步塊的時(shí)候,會(huì)去判斷偏向鎖的狀態(tài)和thread ID,如果偏向鎖狀態(tài)是1,并且thread ID是空的話,將會(huì)使用CAS命令來更新對(duì)象的Mark word。

設(shè)置是否偏向鎖=1,鎖標(biāo)記=01,線程ID設(shè)置為當(dāng)前鎖定該對(duì)象的線程。

下一次該對(duì)象進(jìn)入同步塊的時(shí)候,會(huì)先去判斷鎖定的線程ID和當(dāng)前線程ID是否相等,如果相等的話則不需要執(zhí)行CAS命令,直接進(jìn)入同步塊。

如果這個(gè)時(shí)候有第二個(gè)線程想訪問該對(duì)象的同步塊,因?yàn)楫?dāng)前對(duì)象頭的thread ID是第一個(gè)線程的ID,跟第二個(gè)線程的ID不同。

如果這個(gè)時(shí)候線程1的同步塊已經(jīng)執(zhí)行完畢,那么需要解除偏向鎖的鎖定。

解除鎖定很簡單,就是將線程ID設(shè)置為空,并且將偏向鎖的標(biāo)志位設(shè)為0,

如果這個(gè)時(shí)候線程1的同步塊還在執(zhí)行,那么需要將偏向鎖升級(jí)為輕量級(jí)鎖。

輕量級(jí)鎖thin lock

先看下輕量級(jí)鎖的結(jié)構(gòu):

可以看到Mark word中存放的是棧中鎖記錄的指針和鎖的標(biāo)記=00。

如果對(duì)象現(xiàn)在處于未加鎖狀態(tài),當(dāng)一個(gè)線程嘗試進(jìn)入同步塊的時(shí)候,會(huì)將把對(duì)象頭和當(dāng)前對(duì)象的指針拷貝一份,放在線程的棧中一個(gè)叫做lock record的地方。

然后JVM通過CAS操作,將對(duì)象頭中的指針指向剛剛拷貝的lock record。如果成功,則該線程擁有該對(duì)象的鎖。

實(shí)際上Lock Record和Mark word形成了一個(gè)互相指向?qū)Ψ降那闆r。

下次這個(gè)線程再次進(jìn)入同步塊的時(shí)候,同樣執(zhí)行CAS,比較Mark word中的指針是否和當(dāng)前thread的lock record地址一致,如果一致表明是同一個(gè)線程,可以繼續(xù)持有該鎖。

如果這個(gè)時(shí)候有第二個(gè)線程,也想進(jìn)入該對(duì)象的同步塊,也會(huì)執(zhí)行CAS操作,很明顯會(huì)失敗,因?yàn)閷?duì)象頭中的指針和lock record的地址不一樣。

這個(gè)時(shí)候第二個(gè)線程就會(huì)自旋等待。

那么第一個(gè)線程什么時(shí)候會(huì)釋放鎖呢?

輕量級(jí)鎖在線程退出同步塊的時(shí)候,同樣需要執(zhí)行CAS命令,將鎖標(biāo)記從00替換成01,也就是無鎖狀態(tài)。

重量級(jí)鎖

如果第二個(gè)線程自旋時(shí)間太久,就會(huì)將鎖標(biāo)記替換成10(重量級(jí)鎖),并且設(shè)置重量級(jí)鎖的指針,指向第二個(gè)線程,然后進(jìn)入阻塞狀態(tài)。

當(dāng)?shù)谝粋€(gè)線程退出同步塊的時(shí)候,執(zhí)行CAS命令就會(huì)出錯(cuò),這時(shí)候第一個(gè)線程就知道鎖已經(jīng)膨脹成為重量級(jí)鎖了。

第一個(gè)線程就會(huì)釋放鎖,并且喚醒等待的第二個(gè)線程。

第二個(gè)線程被喚醒之后,重新爭(zhēng)奪鎖。

我們看下重量級(jí)鎖的結(jié)構(gòu):

三種鎖狀態(tài)的不同

偏向鎖,輕量級(jí)鎖和重量級(jí)鎖到底有什么不同了?

這里總結(jié)一下,偏向鎖下次進(jìn)入的時(shí)候不需要執(zhí)行CAS命令,只做線程ID的比較即可。

輕量級(jí)鎖進(jìn)入和退出同步塊都需要執(zhí)行CAS命令,但是輕量級(jí)鎖不會(huì)阻塞,它使用的是自旋命令來獲取鎖。

重量級(jí)鎖不使用自旋,但是會(huì)阻塞線程。!

以上就是詳解JVM系列之對(duì)象的鎖狀態(tài)和同步的詳細(xì)內(nèi)容,更多關(guān)于JVM系列之對(duì)象的鎖狀態(tài)和同步的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java面向?qū)ο笾畠?nèi)部類案例講解

    Java面向?qū)ο笾畠?nèi)部類案例講解

    這篇文章主要介紹了Java面向?qū)ο笾畠?nèi)部類案例講解,本篇文章通過簡要的案例,講解了該項(xiàng)技術(shù)的了解與使用,以下就是詳細(xì)內(nèi)容,需要的朋友可以參考下
    2021-08-08
  • SpringCloud-Alibaba-Sentinel服務(wù)降級(jí),熱點(diǎn)限流,服務(wù)熔斷

    SpringCloud-Alibaba-Sentinel服務(wù)降級(jí),熱點(diǎn)限流,服務(wù)熔斷

    這篇文章主要介紹了SpringCloud-Alibaba-Sentinel服務(wù)降級(jí),熱點(diǎn)限流,服務(wù)熔斷,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-12-12
  • 詳解Spring Cloud 斷路器集群監(jiān)控(Turbine)

    詳解Spring Cloud 斷路器集群監(jiān)控(Turbine)

    這篇文章主要介紹了詳解Spring Cloud 斷路器集群監(jiān)控(Turbine),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-05-05
  • SpringBoot實(shí)現(xiàn)啟動(dòng)類的存放位置

    SpringBoot實(shí)現(xiàn)啟動(dòng)類的存放位置

    這篇文章主要介紹了SpringBoot實(shí)現(xiàn)啟動(dòng)類的存放位置,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-01-01
  • SpringBoot使用classfinal-maven-plugin插件加密Jar包的示例代碼

    SpringBoot使用classfinal-maven-plugin插件加密Jar包的示例代碼

    這篇文章給大家介紹了SpringBoot使用classfinal-maven-plugin插件加密Jar包的實(shí)例,文中通過代碼示例和圖文講解的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2024-02-02
  • Java實(shí)現(xiàn)浪漫流星表白的示例代碼

    Java實(shí)現(xiàn)浪漫流星表白的示例代碼

    本文將利用Java語言實(shí)現(xiàn)浪漫流星表白,可以實(shí)現(xiàn)這些功能:播放音樂、自定義流星數(shù)量、飛行速度、光暈大小、流星大小,自定義表白話語,感興趣的可以學(xué)習(xí)一下
    2022-05-05
  • Java Web Filter 過濾器學(xué)習(xí)教程(推薦)

    Java Web Filter 過濾器學(xué)習(xí)教程(推薦)

    Filter也稱之為過濾器,它是Servlet技術(shù)中最激動(dòng)人心的技術(shù).這篇文章主要介紹了Java Web Filter 過濾器學(xué)習(xí)教程的相關(guān)資料,需要的朋友可以參考下
    2016-05-05
  • java模擬多線程http請(qǐng)求代碼分享

    java模擬多線程http請(qǐng)求代碼分享

    本篇文章給大家分享了java模擬多線程http請(qǐng)求的相關(guān)實(shí)例代碼,對(duì)此有需要的可以跟著測(cè)試下。
    2018-05-05
  • Java Stack與Queue詳解

    Java Stack與Queue詳解

    這篇文章主要介紹了Java Stack與Queue詳解,文中有非常詳細(xì)的代碼示例,對(duì)正在學(xué)習(xí)Java的小伙伴們有很好地幫助,需要的朋友可以參考下
    2021-05-05
  • 解決spring懶加載以及@PostConstruct結(jié)合的坑

    解決spring懶加載以及@PostConstruct結(jié)合的坑

    這篇文章主要介紹了解決spring懶加載以及@PostConstruct結(jié)合的坑,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-12-12

最新評(píng)論