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

jvm細(xì)節(jié)探索之synchronized及實(shí)現(xiàn)問(wèn)題分析

 更新時(shí)間:2017年11月28日 11:01:01   作者:JAVA Miner  
這篇文章主要介紹了jvm細(xì)節(jié)探索之synchronized及實(shí)現(xiàn)問(wèn)題分析,涉及synchronized的字節(jié)碼表示,JVM中鎖的優(yōu)化,對(duì)象頭的介紹等相關(guān)內(nèi)容,具有一定借鑒價(jià)值,需要的朋友可以參考下。

在C程序代碼中我們可以利用操作系統(tǒng)提供的互斥鎖來(lái)實(shí)現(xiàn)同步塊的互斥訪問(wèn)及線程的阻塞及喚醒等工作。然而在Java中除了提供LockAPI外還在語(yǔ)法層面上提供了synchronized關(guān)鍵字來(lái)實(shí)現(xiàn)互斥同步原語(yǔ)。那么到底在JVM內(nèi)部是怎么實(shí)現(xiàn)synchronized關(guān)鍵子的呢?

一、synchronized的字節(jié)碼表示:

在java語(yǔ)言中存在兩種內(nèi)建的synchronized語(yǔ)法:1、synchronized語(yǔ)句;2、synchronized方法。對(duì)于synchronized語(yǔ)句當(dāng)Java源代碼被javac編譯成bytecode的時(shí)候,會(huì)在同步塊的入口位置和退出位置分別插入monitorenter和monitorexit字節(jié)碼指令。而synchronized方法則會(huì)被翻譯成普通的方法調(diào)用和返回指令如:invokevirtual、areturn指令,在VM字節(jié)碼層面并沒(méi)有任何特別的指令來(lái)實(shí)現(xiàn)被synchronized修飾的方法,而是在Class文件的方法表中將該方法的access_flags字段中的synchronized標(biāo)志位置1,表示該方法是同步方法并使用調(diào)用該方法的對(duì)象或該方法所屬的Class在JVM的內(nèi)部對(duì)象表示Klass做為鎖對(duì)象。

二、JVM中鎖的優(yōu)化:

簡(jiǎn)單來(lái)說(shuō)在JVM中monitorenter和monitorexit字節(jié)碼依賴于底層的操作系統(tǒng)的MutexLock來(lái)實(shí)現(xiàn)的,但是由于使用MutexLock需要將當(dāng)前線程掛起并從用戶態(tài)切換到內(nèi)核態(tài)來(lái)執(zhí)行,這種切換的代價(jià)是非常昂貴的;然而在現(xiàn)實(shí)中的大部分情況下,同步方法是運(yùn)行在單線程環(huán)境(無(wú)鎖競(jìng)爭(zhēng)環(huán)境)如果每次都調(diào)用MutexLock那么將嚴(yán)重的影響程序的性能。不過(guò)在jdk1.6中對(duì)鎖的實(shí)現(xiàn)引入了大量的優(yōu)化,如鎖粗化(LockCoarsening)、鎖消除(LockElimination)、輕量級(jí)鎖(LightweightLocking)、偏向鎖(BiasedLocking)、適應(yīng)性自旋(AdaptiveSpinning)等技術(shù)來(lái)減少鎖操作的開(kāi)銷(xiāo)。

鎖粗化(LockCoarsening):也就是減少不必要的緊連在一起的unlock,lock操作,將多個(gè)連續(xù)的鎖擴(kuò)展成一個(gè)范圍更大的鎖。

鎖消除(LockElimination):通過(guò)運(yùn)行時(shí)JIT編譯器的逃逸分析來(lái)消除一些沒(méi)有在當(dāng)前同步塊以外被其他線程共享的數(shù)據(jù)的鎖保護(hù),通過(guò)逃逸分析也可以在線程本地Stack上進(jìn)行對(duì)象空間的分配(同時(shí)還可以減少Heap上的垃圾收集開(kāi)銷(xiāo))。

輕量級(jí)鎖(LightweightLocking):這種鎖實(shí)現(xiàn)的背后基于這樣一種假設(shè),即在真實(shí)的情況下我們程序中的大部分同步代碼一般都處于無(wú)鎖競(jìng)爭(zhēng)狀態(tài)(即單線程執(zhí)行環(huán)境),在無(wú)鎖競(jìng)爭(zhēng)的情況下完全可以避免調(diào)用操作系統(tǒng)層面的重量級(jí)互斥鎖,取而代之的是在monitorenter和monitorexit中只需要依靠一條CAS原子指令就可以完成鎖的獲取及釋放。當(dāng)存在鎖競(jìng)爭(zhēng)的情況下,執(zhí)行CAS指令失敗的線程將調(diào)用操作系統(tǒng)互斥鎖進(jìn)入到阻塞狀態(tài),當(dāng)鎖被釋放的時(shí)候被喚醒(具體處理步驟下面詳細(xì)討論)。

偏向鎖(BiasedLocking):是為了在無(wú)鎖競(jìng)爭(zhēng)的情況下避免在鎖獲取過(guò)程中執(zhí)行不必要的CAS原子指令,因?yàn)镃AS原子指令雖然相對(duì)于重量級(jí)鎖來(lái)說(shuō)開(kāi)銷(xiāo)比較小但還是存在非??捎^的本地延遲(可參考這篇文章)。

適應(yīng)性自旋(AdaptiveSpinning):當(dāng)線程在獲取輕量級(jí)鎖的過(guò)程中執(zhí)行CAS操作失敗時(shí),在進(jìn)入與monitor相關(guān)聯(lián)的操作系統(tǒng)重量級(jí)鎖(mutexsemaphore)前會(huì)進(jìn)入忙等待(Spinning)然后再次嘗試,當(dāng)嘗試一定的次數(shù)后如果仍然沒(méi)有成功則調(diào)用與該monitor關(guān)聯(lián)的semaphore(即互斥鎖)進(jìn)入到阻塞狀態(tài)。

三、對(duì)象頭(ObjectHeader):

在JVM中創(chuàng)建對(duì)象時(shí)會(huì)在對(duì)象前面加上兩個(gè)字大小的對(duì)象頭,在32位機(jī)器上一個(gè)字為32bit,根據(jù)不同的狀態(tài)位MarkWorld中存放不同的內(nèi)容,如上圖所示在輕量級(jí)鎖中,MarkWord被分成兩部分,剛開(kāi)始時(shí)LockWord為被設(shè)置為HashCode、最低三位表示LockWord所處的狀態(tài),初始狀態(tài)為001表示無(wú)鎖狀態(tài)。Klassptr指向Class字節(jié)碼在虛擬機(jī)內(nèi)部的對(duì)象表示的地址。Fields表示連續(xù)的對(duì)象實(shí)例字段。

四、MonitorRecord:

MonitorRecord是線程私有的數(shù)據(jù)結(jié)構(gòu),每一個(gè)線程都有一個(gè)可用monitorrecord列表,同時(shí)還有一個(gè)全局的可用列表;那么這些monitorrecord有什么用呢?每一個(gè)被鎖住的對(duì)象都會(huì)和一個(gè)monitorrecord關(guān)聯(lián)(對(duì)象頭中的LockWord指向monitorrecord的起始地址,由于這個(gè)地址是8byte對(duì)齊的所以LockWord的最低三位可以用來(lái)作為狀態(tài)位),同時(shí)monitorrecord中有一個(gè)Owner字段存放擁有該鎖的線程的唯一標(biāo)識(shí),表示該鎖被這個(gè)線程占用。如下圖所示為MonitorRecord的內(nèi)部結(jié)構(gòu):

Owner:初始時(shí)為NULL表示當(dāng)前沒(méi)有任何線程擁有該monitor record,當(dāng)線程成功擁有該鎖后保存線程唯一標(biāo)識(shí),當(dāng)鎖被釋放時(shí)又設(shè)置為NULL;

EntryQ:關(guān)聯(lián)一個(gè)系統(tǒng)互斥鎖(semaphore),阻塞所有試圖鎖住monitor record失敗的線程。

RcThis:表示blocked或waiting在該monitor record上的所有線程的個(gè)數(shù)。

Nest:用來(lái)實(shí)現(xiàn)重入鎖的計(jì)數(shù)。

HashCode:保存從對(duì)象頭拷貝過(guò)來(lái)的HashCode值(可能還包含GC age)。

Candidate:用來(lái)避免不必要的阻塞或等待線程喚醒,因?yàn)槊恳淮沃挥幸粋€(gè)線程能夠成功擁有鎖,如果每次前一個(gè)釋放鎖的線程喚醒所有正在阻塞或等待的線程,會(huì)引起不必要的上下文切換(從阻塞到就緒然后因?yàn)楦?jìng)爭(zhēng)鎖失敗又被阻塞)從而導(dǎo)致性能?chē)?yán)重下降。Candidate只有兩種可能的值0表示沒(méi)有需要喚醒的線程1表示要喚醒一個(gè)繼任線程來(lái)競(jìng)爭(zhēng)鎖。

五、輕量級(jí)鎖具體實(shí)現(xiàn):

一個(gè)線程能夠通過(guò)兩種方式鎖住一個(gè)對(duì)象:1、通過(guò)膨脹一個(gè)處于無(wú)鎖狀態(tài)(狀態(tài)位001)的對(duì)象獲得該對(duì)象的鎖;2、對(duì)象已經(jīng)處于膨脹狀態(tài)(狀態(tài)位00)但LockWord指向的monitor record的Owner字段為NULL,則可以直接通過(guò)CAS原子指令嘗試將Owner設(shè)置為自己的標(biāo)識(shí)來(lái)獲得鎖。

獲取鎖(monitorenter)的大概過(guò)程如下:

(1)當(dāng)對(duì)象處于無(wú)鎖狀態(tài)時(shí)(RecordWord值為HashCode,狀態(tài)位為001),線程首先從自己的可用moniter record列表中取得一個(gè)空閑的moniter record,初始Nest和Owner值分別被預(yù)先設(shè)置為1和該線程自己的標(biāo)識(shí),一旦monitor record準(zhǔn)備好然后我們通過(guò)CAS原子指令安裝該monitor record的起始地址到對(duì)象頭的LockWord字段來(lái)膨脹(原文為inflate,我覺(jué)得之所以叫inflate主要是由于當(dāng)對(duì)象被膨脹后擴(kuò)展了對(duì)象的大??;為了空間效率,將monitor record結(jié)構(gòu)從對(duì)象頭中抽出去,當(dāng)需要的時(shí)候才將該結(jié)構(gòu)attach到對(duì)象上,但是和這篇Paper有點(diǎn)互相矛盾,兩種實(shí)現(xiàn)方式稍微有點(diǎn)不同)該對(duì)象,如果存在其他線程競(jìng)爭(zhēng)鎖的情況而調(diào)用CAS失敗,則只需要簡(jiǎn)單的回到monitorenter重新開(kāi)始獲取鎖的過(guò)程即可。

(2)對(duì)象已經(jīng)被膨脹同時(shí)Owner中保存的線程標(biāo)識(shí)為獲取鎖的線程自己,這就是重入(reentrant)鎖的情況,只需要簡(jiǎn)單的將Nest加1即可。不需要任何原子操作,效率非常高。

(3)對(duì)象已膨脹但Owner的值為NULL,當(dāng)一個(gè)鎖上存在阻塞或等待的線程同時(shí)鎖的前一個(gè)擁有者剛釋放鎖時(shí)會(huì)出現(xiàn)這種狀態(tài),此時(shí)多個(gè)線程通過(guò)CAS原子指令在多線程競(jìng)爭(zhēng)狀態(tài)下試圖將Owner設(shè)置為自己的標(biāo)識(shí)來(lái)獲得鎖,競(jìng)爭(zhēng)失敗的線程在則會(huì)進(jìn)入到第四種情況(4)的執(zhí)行路徑。

(4)對(duì)象處于膨脹狀態(tài)同時(shí)Owner不為NULL(被鎖住),在調(diào)用操作系統(tǒng)的重量級(jí)的互斥鎖之前先自旋一定的次數(shù),當(dāng)達(dá)到一定的次數(shù)時(shí)如果仍然沒(méi)有成功獲得鎖,則開(kāi)始準(zhǔn)備進(jìn)入阻塞狀態(tài),首先將rfThis的值原子性的加1,由于在加1的過(guò)程中可能會(huì)被其他線程破壞Object和monitor record之間的關(guān)聯(lián),所以在原子性加1后需要再進(jìn)行一次比較以確保LockWord的值沒(méi)有被改變,當(dāng)發(fā)現(xiàn)被改變后則要重新進(jìn)行monitorenter過(guò)程。同時(shí)再一次觀察Owner是否為NULL,如果是則調(diào)用CAS參與競(jìng)爭(zhēng)鎖,鎖競(jìng)爭(zhēng)失敗則進(jìn)入到阻塞狀態(tài)。

釋放鎖(monitorexit)的大概過(guò)程如下:

(1)首先檢查該對(duì)象是否處于膨脹狀態(tài)并且該線程是這個(gè)鎖的擁有者,如果發(fā)現(xiàn)不對(duì)則拋出異常;

(2)檢查Nest字段是否大于1,如果大于1則簡(jiǎn)單的將Nest減1并繼續(xù)擁有鎖,如果等于1,則進(jìn)入到第(3)步;

(3)檢查rfThis是否大于0,設(shè)置Owner為NULL然后喚醒一個(gè)正在阻塞或等待的線程再一次試圖獲取鎖,如果等于0則進(jìn)入到第(4)步

(4)縮小(deflate)一個(gè)對(duì)象,通過(guò)將對(duì)象的LockWord置換回原來(lái)的HashCode值來(lái)解除和monitor record之間的關(guān)聯(lián)來(lái)釋放鎖,同時(shí)將monitor record放回到線程是有的可用monitor record列表。

總結(jié)

參考:《深入理解Java虛擬機(jī) JVM高級(jí)特性與最佳實(shí)踐(周志明)

以上就是本文關(guān)于jvm細(xì)節(jié)探索之synchronized及實(shí)現(xiàn)問(wèn)題分析的全部?jī)?nèi)容,希望對(duì)大家有所幫助。如有不足之處,歡迎留言指出。感謝朋友們對(duì)本站的支持!

相關(guān)文章

  • java用靜態(tài)工廠代替構(gòu)造函數(shù)使用方法和優(yōu)缺點(diǎn)

    java用靜態(tài)工廠代替構(gòu)造函數(shù)使用方法和優(yōu)缺點(diǎn)

    這篇文章主要介紹了java用靜態(tài)工廠代替構(gòu)造函數(shù)使用方法和優(yōu)缺點(diǎn),需要的朋友可以參考下
    2014-02-02
  • 詳解Java8中CompletableFuture類的使用

    詳解Java8中CompletableFuture類的使用

    Java?8中引入了CompletableFuture類,它是一種方便的異步編程工具,可以處理各種異步操作,本文將詳細(xì)介紹CompletableFuture的使用方式,希望對(duì)大家有所幫助
    2023-04-04
  • mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說(shuō)明

    mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說(shuō)明

    這篇文章主要介紹了mybatis 集合嵌套查詢和集合嵌套結(jié)果的區(qū)別說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-09-09
  • Java語(yǔ)言之包和繼承詳解

    Java語(yǔ)言之包和繼承詳解

    這篇文章主要介紹了java的包和繼承,結(jié)合實(shí)例形式詳細(xì)分析了Java繼承的概念、原理、用法及相關(guān)操作注意事項(xiàng),需要的朋友可以參考下
    2021-09-09
  • springboot如何接收復(fù)雜參數(shù)(同時(shí)接收J(rèn)SON與文件)

    springboot如何接收復(fù)雜參數(shù)(同時(shí)接收J(rèn)SON與文件)

    文章介紹了在Spring Boot中同時(shí)處理JSON和文件上傳時(shí)使用`@RequestPart`注解的方法,`@RequestPart`可以接收多種格式的參數(shù),包括JSON和文件,并且可以作為`multipart/form-data`格式中的key
    2025-02-02
  • 用Java編程輸出萬(wàn)年歷的功能實(shí)現(xiàn)

    用Java編程輸出萬(wàn)年歷的功能實(shí)現(xiàn)

    這篇文章主要介紹了用Java編程輸出萬(wàn)年歷的功能實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • Java設(shè)計(jì)模式之單例模式Singleton Pattern詳解

    Java設(shè)計(jì)模式之單例模式Singleton Pattern詳解

    這篇文章主要介紹了Java設(shè)計(jì)模式之單例模式Singleton Pattern詳解,一些常用的工具類、線程池、緩存,數(shù)據(jù)庫(kù),數(shù)據(jù)庫(kù)連接池、賬戶登錄系統(tǒng)、配置文件等程序中可能只允許我們創(chuàng)建一個(gè)對(duì)象,這就需要單例模式,需要的朋友可以參考下
    2023-12-12
  • Spring Cloud 配置中心內(nèi)容加密的配置方法

    Spring Cloud 配置中心內(nèi)容加密的配置方法

    這篇文章主要介紹了Spring Cloud 配置中心內(nèi)容加密的配置方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2018-06-06
  • 導(dǎo)入renren-fast出現(xiàn)問(wèn)題以及解決方案

    導(dǎo)入renren-fast出現(xiàn)問(wèn)題以及解決方案

    文章介紹了在導(dǎo)入renren-fast項(xiàng)目時(shí)遇到的maven繼承parent問(wèn)題,并提供了解決方案,即在pom文件中添加``標(biāo)簽,此外,還詳細(xì)解釋了Maven的``標(biāo)簽的作用以及MAVEN構(gòu)建jar包時(shí)的查找順序
    2024-11-11
  • Maven install 報(bào)錯(cuò)

    Maven install 報(bào)錯(cuò)"程序包不存在"問(wèn)題的解決方法

    這篇文章主要介紹了Maven install 報(bào)錯(cuò)"程序包不存在"問(wèn)題的解決方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07

最新評(píng)論

诸城市| 政和县| 五寨县| 岫岩| 蒙阴县| 开鲁县| 崇仁县| 定西市| 博野县| 睢宁县| 南乐县| 淮阳县| 南投县| 溧阳市| 鸡东县| 仁寿县| 龙川县| 惠水县| 扶风县| 镇远县| 会同县| 璧山县| 西华县| 泰宁县| 报价| 个旧市| 巴彦淖尔市| 西青区| 荃湾区| 潼关县| 双流县| 金山区| 泽库县| 凤翔县| 金湖县| 崇信县| 泰宁县| 巧家县| 高碑店市| 玉门市| 芜湖县|