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

Java多線程揭秘之synchronized工作原理

 更新時(shí)間:2021年10月18日 09:33:28   作者:春風(fēng)~十一載  
synchronized算是多線程中非常常用的加鎖方式了,但很多人都不太理解其底層的工作原理。本篇文章博主用盡可能通俗易懂的方式來(lái)帶大家去看看synchronized究竟是怎么加鎖的

在學(xué)習(xí)本篇文章時(shí),如果有不太懂的地方,大家也可以先看看博主上一篇文章,鎖的這部分內(nèi)容是面試中很常見(jiàn)的問(wèn)題,多學(xué)學(xué)對(duì)自己是非常有幫助的。同時(shí),朋友們?nèi)绻惺裁磫?wèn)題都可以隨時(shí)和我探討,大家一起進(jìn)步!

一. 特性

這部分內(nèi)容在上篇文章中的 synchronized充當(dāng)了哪些鎖部分已經(jīng)介紹過(guò)了哦,沒(méi)有看的小伙伴可以去看看synchronized的特性

二. 加鎖過(guò)程(鎖升級(jí)/鎖膨脹)

在Java中JVM虛擬機(jī)將synchronized鎖分為無(wú)鎖、偏向鎖、輕量級(jí)鎖、重量級(jí)鎖狀態(tài)。會(huì)根據(jù)不同的情況,進(jìn)行不同的升級(jí)操作

在這里插入圖片描述

1. 無(wú)鎖狀態(tài)

此狀態(tài)理解起來(lái)較為簡(jiǎn)單,沒(méi)有進(jìn)行線程任務(wù)時(shí)最開(kāi)始的狀態(tài)就是無(wú)鎖狀態(tài)。

2. 偏向鎖

  • 偏向鎖類似于一種樂(lè)觀鎖,當(dāng)一個(gè)線程在執(zhí)行任務(wù)時(shí),偏向鎖會(huì)給這個(gè)線程設(shè)定一個(gè)標(biāo)記(并不是真正地加鎖),如果后續(xù)沒(méi)有其他線程來(lái)競(jìng)爭(zhēng)這個(gè)鎖,那么這個(gè)偏向鎖就不會(huì)再進(jìn)行其他的任何操作了,有效避免了因?yàn)榧渔i過(guò)程而產(chǎn)生的內(nèi)存開(kāi)銷問(wèn)題
  • 若有其他線程也競(jìng)爭(zhēng)這把鎖,那么此時(shí)第一個(gè)線程會(huì)立馬把鎖拿到(因?yàn)橹暗谝粋€(gè)線程已經(jīng)有了偏向鎖標(biāo)記,所以很容易拿到)然后進(jìn)入輕量級(jí)鎖的狀態(tài)

偏向鎖的大體思路是能不加鎖就盡量不加鎖避免內(nèi)存開(kāi)銷,只做上標(biāo)記即可,但如果實(shí)在要加鎖,也會(huì)因?yàn)闃?biāo)記的存在而立馬把鎖拿到(類似于高考填志愿保底心態(tài))

3. 輕量級(jí)鎖

當(dāng)進(jìn)入輕量級(jí)鎖鎖狀態(tài)(自適應(yīng)自旋鎖)后,是完全在用戶態(tài)上實(shí)現(xiàn)的,且是基于CAS來(lái)完成的操作,因?yàn)檫@個(gè)狀態(tài)不涉及到內(nèi)核態(tài)和用戶態(tài)的切換,也不涉及到線程的阻塞和調(diào)度過(guò)程。所以并不會(huì)對(duì)系統(tǒng)的內(nèi)存有著過(guò)于高的開(kāi)銷,因此可以保證更高效地獲取到鎖(一個(gè)線程釋放鎖后,另一個(gè)線程會(huì)馬上獲取到鎖)

具體步驟

  • 通過(guò) CAS 檢查并更新一塊內(nèi)存 (比如 null => 該線程引用)
  • 如果更新成功, 則認(rèn)為加鎖成功
  • 如果更新失敗, 則認(rèn)為鎖被占用, 繼續(xù)自旋式的等待(并不放棄 CPU)由于自旋操作可能會(huì)一直讓CPU 空轉(zhuǎn),比較浪費(fèi) CPU 資源,因此此處的自旋不會(huì)一直持續(xù)進(jìn)行,而是達(dá)到一定的時(shí)間(重試)次數(shù),就不再自旋了,也就是所謂的 “自適應(yīng)”(根據(jù)情況來(lái))

4. 重量級(jí)鎖

當(dāng)鎖的競(jìng)爭(zhēng)變得非常激烈時(shí),如果再按照之前自旋的方式,那么對(duì)于CPU的開(kāi)銷是非常高的,而且此時(shí)自旋還不能快速地獲取到鎖的狀態(tài),那么此時(shí)就會(huì)變成重量級(jí)鎖(掛起等待鎖),對(duì)于掛起等待鎖來(lái)說(shuō),鎖的等待過(guò)程是釋放CPU的過(guò)程,此時(shí)會(huì)節(jié)省CPU的開(kāi)銷,但付出的代價(jià)是引入了線程的阻塞和調(diào)度的開(kāi)銷(以CPU資源換取性能)
具體過(guò)程
此處的重量級(jí)鎖就是用到了內(nèi)核提供的mutex,要執(zhí)行加鎖操作,首先會(huì)進(jìn)入內(nèi)核態(tài),在內(nèi)核態(tài)判定當(dāng)前的鎖是否已經(jīng)被占用,若該鎖沒(méi)有被占用,則加鎖成功,切換回用戶態(tài);若該鎖被占用,則加鎖失敗,此時(shí)線程進(jìn)入鎖的等待隊(duì)列去掛起等待,直到鎖被其他線程釋放后,操作系統(tǒng)才會(huì)喚醒掛起等待鎖的這個(gè)線程,最后這個(gè)線程才會(huì)獲取到鎖

5. 總結(jié)

  • 鎖升級(jí)(鎖膨脹)的過(guò)程完全是synchronized內(nèi)部自適應(yīng)完成的,即根據(jù)不同的情況(即鎖沖突的高或低狀態(tài))來(lái)升級(jí)或降級(jí)成對(duì)應(yīng)的狀態(tài),不需要用戶或者程序員去干預(yù),因此使用起來(lái)會(huì)比較方便。
  • 注意, synchronized在有些JVM版本上是可以同時(shí)實(shí)現(xiàn)降級(jí)和升級(jí)的自適應(yīng)的,但在有些JVM上只能實(shí)現(xiàn)升級(jí)的自適應(yīng)。

三. 鎖優(yōu)化

1. 鎖消除

JVM和編譯器提供了一個(gè)很好的功能,能判斷某段代碼是否有加鎖的必要(根據(jù)情況選擇是否需要加鎖),以防開(kāi)發(fā)人員加錯(cuò)鎖而造成無(wú)緣無(wú)故開(kāi)銷很大系統(tǒng)內(nèi)存的情況。
例子
Java提供了兩個(gè)類,StringBuilderStringBuffer,其中,前者不會(huì)考慮線程安全問(wèn)題,而后者中的每個(gè)方法都帶有了synchronized以確保線程安全。但我們平常在單線程下,這個(gè)加鎖是沒(méi)有必要的,會(huì)白白浪費(fèi)很多內(nèi)存資源,這時(shí)候,如果開(kāi)發(fā)人員不小心在單線程中使用了StringBuffer,那么編譯器和JVM也會(huì)對(duì)其進(jìn)行一定的優(yōu)化,去把這個(gè)鎖消除。
注意,編譯器的判斷也不是每次完全都是正確的,不會(huì)每次都會(huì)鎖消除,因此,還是要提醒大家在寫(xiě)代碼過(guò)程中自己還是要盡量避免出現(xiàn)此類錯(cuò)誤

2. 鎖粗化

介紹鎖粗化之前,首先大家得知道鎖的粗細(xì)的含義:

  • 如果synchronized代碼塊中包含的代碼比較多,則認(rèn)為鎖比較粗
  • 如果synchronized代碼塊中包含的代碼比較少,則認(rèn)為鎖比較細(xì)

那么實(shí)際開(kāi)發(fā)中,到底是鎖粗一點(diǎn)好還是細(xì)一點(diǎn)好呢?這個(gè)還是根據(jù)情況來(lái)決定的,雖然當(dāng)鎖里面的代碼量少時(shí)會(huì)減少線程之間的鎖沖突概率,但是有的情況下,反而當(dāng)鎖里面的代碼量較多時(shí),運(yùn)行效率才會(huì)更高:

void func(){
        synchronized (this){
            //任務(wù)1
        }
        synchronized (this){
            //任務(wù)2
        }
        synchronized (this){
            //任務(wù)3
        }
    }

大家先來(lái)看一看這段代碼,這段代碼是細(xì)鎖的情況(一個(gè)鎖中的代碼量較少),那么其執(zhí)行效率怎么樣呢?顯然是不太高的,每次加一次鎖都會(huì)進(jìn)行一定的內(nèi)存開(kāi)銷,因此我們很有必要對(duì)其進(jìn)行一定地改進(jìn),讓鎖粗化:

void func(){
        synchronized (this){
            //任務(wù)1
            //任務(wù)2
            //任務(wù)3
        }
    }

可以看出來(lái),當(dāng)鎖粗化的時(shí)候,會(huì)大大提高代碼的執(zhí)行效率
就好比出門(mén)買(mǎi)物品A和物品B,我們通常會(huì)盡可能地出一次門(mén),將二者一塊買(mǎi)好再回家,而不是先把物品A買(mǎi)好放到家里再出門(mén)買(mǎi)物品B,這樣顯然效率是非常低的,而且還很浪費(fèi)體力

到此這篇關(guān)于Java多線程揭秘之synchronized工作原理的文章就介紹到這了,更多相關(guān)Java synchronized內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot開(kāi)發(fā)實(shí)戰(zhàn)之自動(dòng)配置

    SpringBoot開(kāi)發(fā)實(shí)戰(zhàn)之自動(dòng)配置

    SpringBoot的核心就是自動(dòng)配置,自動(dòng)配置又是基于條件判斷來(lái)配置Bean,下面這篇文章主要給大家介紹了關(guān)于SpringBoot開(kāi)發(fā)實(shí)戰(zhàn)之自動(dòng)配置的相關(guān)資料,需要的朋友可以參考下
    2021-08-08
  • 解決idea每次新建項(xiàng)目都需要重新指定maven目錄

    解決idea每次新建項(xiàng)目都需要重新指定maven目錄

    這篇文章主要介紹了解決idea每次新建項(xiàng)目都需要配置maven,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • java實(shí)現(xiàn)雪花算法ID生成器工具類

    java實(shí)現(xiàn)雪花算法ID生成器工具類

    本文主要介紹了java實(shí)現(xiàn)雪花算法ID生成器工具類,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-07-07
  • IDEA中程序包Org.Springframework.Boot不存在問(wèn)題及解決

    IDEA中程序包Org.Springframework.Boot不存在問(wèn)題及解決

    這篇文章主要介紹了IDEA中程序包Org.Springframework.Boot不存在問(wèn)題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-07-07
  • 一文帶你回顧Java中的垃圾回收機(jī)制

    一文帶你回顧Java中的垃圾回收機(jī)制

    這篇文章主要給大家介紹了關(guān)于Java中垃圾回收機(jī)制的相關(guān)資料, Java 程序,內(nèi)存是托管于 JVM 的,即對(duì)象的創(chuàng)建和內(nèi)存的回收都是由 JVM 自行完成的,開(kāi)發(fā)人員是無(wú)權(quán)干涉的,只能盡量去優(yōu)化,需要的朋友可以參考下
    2021-08-08
  • Java中while語(yǔ)句的簡(jiǎn)單知識(shí)及應(yīng)用

    Java中while語(yǔ)句的簡(jiǎn)單知識(shí)及應(yīng)用

    這篇文章主要給大家介紹了關(guān)于Java中while語(yǔ)句的簡(jiǎn)單知識(shí)及應(yīng)用的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • JSP 開(kāi)發(fā)之hibernate的hql查詢多對(duì)多查詢

    JSP 開(kāi)發(fā)之hibernate的hql查詢多對(duì)多查詢

    這篇文章主要介紹了JSP 開(kāi)發(fā)之hibernate的hql查詢多對(duì)多查詢的相關(guān)資料,希望通過(guò)本文能幫助到大家,需要的朋友可以參考下
    2017-09-09
  • 一文帶你弄懂Java中線程池的原理

    一文帶你弄懂Java中線程池的原理

    工作中,我們經(jīng)常使用線程池,但是你真的了解線程池的原理嗎?同時(shí),線程池工作原理和底層實(shí)現(xiàn)原理也是面試經(jīng)常問(wèn)的考題,所以,今天我們一起聊聊線程池的原理吧
    2022-12-12
  • 如何使用會(huì)話Cookie和Java實(shí)現(xiàn)JWT身份驗(yàn)證

    如何使用會(huì)話Cookie和Java實(shí)現(xiàn)JWT身份驗(yàn)證

    這篇文章主要介紹了如何使用會(huì)話Cookie和Java實(shí)現(xiàn)JWT身份驗(yàn)證,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下
    2021-03-03
  • java簡(jiǎn)單實(shí)現(xiàn)桌球滾動(dòng)效果

    java簡(jiǎn)單實(shí)現(xiàn)桌球滾動(dòng)效果

    這篇文章主要為大家詳細(xì)介紹了java簡(jiǎn)單實(shí)現(xiàn)桌球滾動(dòng)效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-10-10

最新評(píng)論