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

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

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

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

一. 特性

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

二. 加鎖過程(鎖升級/鎖膨脹)

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

在這里插入圖片描述

1. 無鎖狀態(tài)

此狀態(tài)理解起來較為簡單,沒有進行線程任務(wù)時最開始的狀態(tài)就是無鎖狀態(tài)。

2. 偏向鎖

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

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

3. 輕量級鎖

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

具體步驟

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

4. 重量級鎖

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

5. 總結(jié)

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

三. 鎖優(yōu)化

1. 鎖消除

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

2. 鎖粗化

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

  • 如果synchronized代碼塊中包含的代碼比較多,則認為鎖比較粗
  • 如果synchronized代碼塊中包含的代碼比較少,則認為鎖比較細

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

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

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

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

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

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

相關(guān)文章

  • Spring?RestTemplate遠程調(diào)用過程

    Spring?RestTemplate遠程調(diào)用過程

    這篇文章主要介紹了Spring?RestTemplate遠程調(diào)用過程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-11-11
  • 如何兩步解決maven依賴導(dǎo)入失敗的問題

    如何兩步解決maven依賴導(dǎo)入失敗的問題

    這篇文章主要介紹了如何兩步解決maven依賴導(dǎo)入失敗的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • java遍歷途中修改數(shù)據(jù)及刪除數(shù)據(jù)的方法總結(jié)

    java遍歷途中修改數(shù)據(jù)及刪除數(shù)據(jù)的方法總結(jié)

    在使用java的集合類遍歷數(shù)據(jù)的時候,在某些情況下可能需要對某些數(shù)據(jù)進行刪除,下面這篇文章主要給大家介紹了關(guān)于java遍歷途中修改數(shù)據(jù)及刪除數(shù)據(jù)的方法總結(jié),需要的朋友可以參考下
    2023-10-10
  • JavaMail實現(xiàn)郵件發(fā)送的方法

    JavaMail實現(xiàn)郵件發(fā)送的方法

    這篇文章主要介紹了JavaMail實現(xiàn)郵件發(fā)送的方法,實例分析了java實現(xiàn)郵件發(fā)送的相關(guān)技巧,非常具有實用價值,需要的朋友可以參考下
    2015-04-04
  • Java png圖片修改像素rgba值的操作

    Java png圖片修改像素rgba值的操作

    這篇文章主要介紹了Java png圖片修改像素rgba值的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • java jni調(diào)用c函數(shù)實例分享(java調(diào)用c函數(shù))

    java jni調(diào)用c函數(shù)實例分享(java調(diào)用c函數(shù))

    Java代碼中調(diào)用C/C++代碼,當然是使用JNI,JNI是Java native interface的簡寫,可以譯作Java原生接口,下面看實例吧
    2013-12-12
  • JDK完全卸載超詳細步驟

    JDK完全卸載超詳細步驟

    這篇文章主要給大家介紹了關(guān)于JDK完全卸載超詳細步驟的相關(guān)資料,在安裝JDK之前,最好將原來可能安裝過的JDK卸載掉,以免影響到新JDK的使用,需要的朋友可以參考下
    2023-08-08
  • Oracle+Mybatis的foreach insert批量插入報錯的快速解決辦法

    Oracle+Mybatis的foreach insert批量插入報錯的快速解決辦法

    本文給大家介紹Oracle+Mybatis的foreach insert批量插入報錯的快速解決辦法,非常不錯,具有參考借鑒價值,感興趣的朋友參考下吧
    2016-08-08
  • spring如何使用xml裝配bean

    spring如何使用xml裝配bean

    這篇文章主要介紹了spring如何使用xml裝配bean,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-11-11
  • 關(guān)于分布式鎖(Redisson)的原理分析

    關(guān)于分布式鎖(Redisson)的原理分析

    這篇文章主要介紹了關(guān)于分布式鎖(Redisson)的原理,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-08-08

最新評論

定陶县| 绍兴县| 辽源市| 普兰县| 洮南市| 闵行区| 新绛县| 蓬莱市| 义马市| 贵德县| 韩城市| 临高县| 怀集县| 呈贡县| 雷州市| 滨海县| 肃南| 葵青区| 长子县| 遵义市| 宜阳县| 罗定市| 石门县| 厦门市| 子洲县| 天长市| 波密县| 政和县| 仲巴县| 绥芬河市| 呼和浩特市| 沽源县| 平乐县| 民乐县| 祁门县| 嵩明县| 金平| 岳西县| 巧家县| 南皮县| 屏南县|