日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java如何避免重量级锁,Java 中锁是如何一步步膨胀的(偏向锁、轻量级锁、重量级锁)...

發(fā)布時(shí)間:2023/12/1 java 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java如何避免重量级锁,Java 中锁是如何一步步膨胀的(偏向锁、轻量级锁、重量级锁)... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

重量級(jí)鎖(Mutex Lock)

偏向鎖(比較 ThreadID)

偏向鎖獲取過程

偏向鎖的釋放

輕量級(jí)鎖(自旋)

輕量級(jí)鎖的加鎖過程

輕量級(jí)鎖的釋放

總結(jié)

重量級(jí)鎖(Mutex Lock)

Synchronized 是通過對(duì)象內(nèi)部的一個(gè)叫做監(jiān)視器鎖(monitor)來實(shí)現(xiàn)的。但是監(jiān)視器鎖本質(zhì)又是依賴于底層的操作系統(tǒng)的 Mutex Lock 來實(shí)現(xiàn)的。而操作系統(tǒng)實(shí)現(xiàn)線程之間的切換這就需要從用戶態(tài)轉(zhuǎn)換到核心態(tài),這個(gè)成本非常高,狀態(tài)之間的轉(zhuǎn)換需要相對(duì)比較長(zhǎng)的時(shí)間,這就是為什么 Synchronized 效率低的原因。因此,這種依賴于操作系統(tǒng) Mutex Lock 所實(shí)現(xiàn)的鎖我們稱之為“重量級(jí)鎖”。JDK 中對(duì) Synchronized 做的種種優(yōu)化,其核心都是為了減少這種重量級(jí)鎖的使用。JDK1.6 以后,為了減少獲得鎖和釋放鎖所帶來的性能消耗,提高性能,引入了自旋鎖、自適應(yīng)自旋鎖、輕量級(jí)鎖和偏向鎖。

明確 Java 線程切換的代價(jià),是理解java中各種鎖的優(yōu)缺點(diǎn)的基礎(chǔ)之一。

Java 對(duì)象頭中 markword 結(jié)構(gòu)。Java 對(duì)象的內(nèi)存布局及訪問方式

偏向鎖(比較 ThreadID)

Hotspot 的作者經(jīng)過以往的研究發(fā)現(xiàn)大多數(shù)情況下鎖不僅不存在多線程競(jìng)爭(zhēng),而且總是由同一線程多次獲得。偏向鎖的目的是在某個(gè)線程獲得鎖之后,消除這個(gè)線程鎖重入(CAS)的開銷,看起來讓這個(gè)線程得到了偏護(hù)。引入偏向鎖是為了在無多線程競(jìng)爭(zhēng)的情況下盡量減少不必要的輕量級(jí)鎖執(zhí)行路徑,因?yàn)檩p量級(jí)鎖的獲取及釋放依賴多次 CAS 原子指令,而偏向鎖只需要在置換 ThreadID 的時(shí)候依賴一次 CAS 原子指令(由于一旦出現(xiàn)多線程競(jìng)爭(zhēng)的情況就必須撤銷偏向鎖,所以偏向鎖的撤銷操作的性能損耗必須小于節(jié)省下來的 CAS 原子指令的性能消耗)。輕量級(jí)鎖是為了在線程交替執(zhí)行同步塊時(shí)提高性能,而偏向鎖則是在只有一個(gè)線程執(zhí)行同步塊時(shí)進(jìn)一步提高性能。

偏向鎖獲取過程

訪問 Mark Word 中鎖標(biāo)志位是否為 01,是的話查看偏向鎖的標(biāo)識(shí),如果是 1,則確認(rèn)為可偏向狀態(tài);如果是 0 則為無鎖狀態(tài),直接通過 CAS 操作競(jìng)爭(zhēng)鎖,如果競(jìng)爭(zhēng)失敗,執(zhí)行4。

如果為可偏向狀態(tài),則測(cè)試線程 ID 是否指向當(dāng)前線程,如果是,進(jìn)入步驟5,否則進(jìn)入步驟3。

如果線程 ID 并未指向當(dāng)前線程,則通過 CAS 操作競(jìng)爭(zhēng)鎖。如果競(jìng)爭(zhēng)成功,則將 Mark Word 中線程 ID 設(shè)置為當(dāng)前線程 ID,然后執(zhí)行5;如果競(jìng)爭(zhēng)失敗,執(zhí)行4。

如果 CAS 獲取偏向鎖失敗,則表示有競(jìng)爭(zhēng),開始鎖撤銷。

執(zhí)行同步代碼。

偏向鎖的釋放

偏向鎖使用了一種等到競(jìng)爭(zhēng)出現(xiàn)才釋放鎖的機(jī)制,所以當(dāng)其他線程嘗試競(jìng)爭(zhēng)偏向鎖時(shí),持有偏向鎖的線程才會(huì)釋放鎖,線程不會(huì)主動(dòng)去釋放偏向鎖。

當(dāng)獲得偏向鎖的線程到達(dá)全局安全點(diǎn)(safepoint)時(shí)暫停該線程,檢查該線程的狀態(tài)。

如果該線程存活且沒有退出同步代碼塊,則升級(jí)為輕量級(jí)鎖,并喚醒該線程從安全點(diǎn)繼續(xù)執(zhí)行。

如果該線程沒有存活或者該線程已退出同步代碼塊,則將偏向鎖撤銷為無鎖狀態(tài)(鎖標(biāo)志位 01,偏向鎖標(biāo)識(shí) 0)喚醒該線程。

到達(dá)安全點(diǎn) safepoint 會(huì)導(dǎo)致 stop the word,時(shí)間很短。

輕量級(jí)鎖(自旋)

輕量級(jí)是相對(duì)于使用操作系統(tǒng)互斥量來實(shí)現(xiàn)的傳統(tǒng)鎖而言的。但是,首先需要強(qiáng)調(diào)一點(diǎn)的是,輕量級(jí)鎖并不是用來代替重量級(jí)鎖的,它的本意是在沒有多線程競(jìng)爭(zhēng)的前提下,減少傳統(tǒng)的重量級(jí)鎖使用產(chǎn)生的性能消耗。在解釋輕量級(jí)鎖的執(zhí)行過程之前,先明白一點(diǎn),輕量級(jí)鎖所適應(yīng)的場(chǎng)景是線程交替執(zhí)行同步塊的情況,如果存在同一時(shí)間訪問同一鎖的情況,就會(huì)導(dǎo)致輕量級(jí)鎖膨脹為重量級(jí)鎖。

輕量級(jí)鎖的加鎖過程

1、訪問對(duì)象的 Mark Word 中鎖標(biāo)識(shí)位,如果為 00,JVM 會(huì)先在當(dāng)前線程的棧幀中建立一個(gè)名為鎖記錄(Lock Record)的空間,用于存儲(chǔ)鎖對(duì)象目前的 Mark Word 的拷貝,官方稱之為 Displaced Mark Word。這時(shí)候線程堆棧與對(duì)象頭的狀態(tài)如圖所示。(注:該圖僅作為參考,我認(rèn)為該圖可能存在問題)

2、將對(duì)象頭中的 Mark Word 復(fù)制到鎖記錄中;

3、拷貝成功后,虛擬機(jī)將使用 CAS 操作嘗試將對(duì)象的 Mark Word 更新為指向 Lock Record 的指針,并將 Lock Record 里的 owner 指針指向 object mark word。如果更新成功,則執(zhí)行步驟4,否則執(zhí)行步驟5。

4、如果這個(gè)更新動(dòng)作成功了,那么這個(gè)線程就擁有了該對(duì)象的鎖,此時(shí) Mark Word 的鎖標(biāo)識(shí)為 00,這時(shí)候線程堆棧與對(duì)象頭的狀態(tài)如圖所示。(注:該圖僅作為參考,我認(rèn)為該圖可能存在問題)

5、如果這個(gè)更新操作失敗了,虛擬機(jī)首先會(huì)檢查對(duì)象的 Mark Word 是否指向當(dāng)前線程的棧幀,如果是就說明當(dāng)前線程已經(jīng)擁有了這個(gè)對(duì)象的鎖,那就可以直接進(jìn)入同步塊繼續(xù)執(zhí)行。否則當(dāng)前線程便嘗試使用自旋來獲取鎖(自旋就是為了不讓線程阻塞,而采用循環(huán)去獲取鎖的過程),自旋達(dá)到一定次數(shù)后 CAS 操作依然沒有成功,輕量級(jí)鎖就要膨脹為重量級(jí)鎖,鎖標(biāo)識(shí)設(shè)置為 10,Mark Word 中存儲(chǔ)的就是指向重量級(jí)鎖(monitor)的指針,當(dāng)前線程以及后面等待鎖的線程便會(huì)進(jìn)入阻塞狀態(tài)。

輕量級(jí)鎖的釋放

輕量級(jí)鎖解鎖時(shí),持有鎖的線程會(huì)使用 CAS 原子操作將 Mark Word 替換回到對(duì)象頭,如果成功,則表示沒有競(jìng)爭(zhēng)發(fā)生。如果失敗,釋放鎖并喚醒那些被掛起的線程。

總結(jié)

偏向鎖

偏向鎖只會(huì)在第一次請(qǐng)求鎖時(shí)使用 CAS 操作,并在鎖對(duì)象的標(biāo)記字段中記錄當(dāng)前線程 ID。在此后的運(yùn)行過程中,僅需比較線程 ID,消除這個(gè)線程鎖重入(CAS)的開銷。針對(duì)的是鎖僅會(huì)被同一線程持有的狀況。

輕量級(jí)鎖

輕量級(jí)鎖采用 CAS 操作,減少了傳統(tǒng)的重量級(jí)鎖使用產(chǎn)生的性能消耗。針對(duì)的是多個(gè)線程在不同時(shí)間段申請(qǐng)同一把鎖的情況。

重量級(jí)鎖

重量級(jí)鎖會(huì)阻塞、喚醒請(qǐng)求加鎖的線程,會(huì)導(dǎo)致線程上下文切換。針對(duì)的是多個(gè)線程同時(shí)競(jìng)爭(zhēng)同一把鎖的情況。JVM 采用自適應(yīng)自旋,來避免在面對(duì)非常小的同步代碼塊時(shí),仍會(huì)被阻塞和喚醒的狀況。

參考文章:

https://blog.csdn.net/zhao_miao/article/details/84500771

https://blog.csdn.net/zqz_zqz/article/details/70233767

總結(jié)

以上是生活随笔為你收集整理的Java如何避免重量级锁,Java 中锁是如何一步步膨胀的(偏向锁、轻量级锁、重量级锁)...的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。