<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          13 張圖,深入理解干翻 Synchronized

          共 12624字,需瀏覽 26分鐘

           ·

          2023-05-26 03:29

          前言

          分享一篇優(yōu)質(zhì)文章給你。

          本文帶讀者們由淺入深理解Synchronized,讓讀者們也能與面試官瘋狂對線,同時寫出高性能的代碼和架構(gòu)。

          在并發(fā)編程中Synchronized一直都是元老級的角色,Jdk 1.6以前大家都稱呼它為重量級鎖,相對于J U C包提供的Lock,它會顯得笨重,不過隨著Jdk 1.6Synchronized進(jìn)行各種優(yōu)化后,Synchronized性能已經(jīng)非??炝?。

          內(nèi)容大綱 1f4d0a707b7e7c7ee8af90f19ed2858e.webpSynchronized使用方式

          SynchronizedJava提供的同步關(guān)鍵字,在多線程場景下,對共享資源代碼段進(jìn)行讀寫操作(必須包含寫操作,光讀不會有線程安全問題,因為讀操作天然具備線程安全特性),可能會出現(xiàn)線程安全問題,我們可以使用Synchronized鎖定共享資源代碼段,達(dá)到互斥mutualexclusion)效果,保證線程安全。

          共享資源代碼段又稱為臨界區(qū)critical section),保證臨界區(qū)互斥,是指執(zhí)行臨界區(qū)critical section)的只能有一個線程執(zhí)行,其他線程阻塞等待,達(dá)到排隊效果。

          b98ae153d90fc739d67f42902626e5c3.webp

          Synchronized的食用方式有三種

          • 修飾普通函數(shù),監(jiān)視器鎖(monitor)便是對象實(shí)例(this
          • 修飾靜態(tài)靜態(tài)函數(shù),視器鎖(monitor)便是對象的Class實(shí)例(每個對象只有一個Class實(shí)例)
          • 修飾代碼塊,監(jiān)視器鎖(monitor)是指定對象實(shí)例

          普通函數(shù)

          普通函數(shù)使用Synchronized的方式很簡單,在訪問權(quán)限修飾符函數(shù)返回類型間加上Synchronized。

          40bbae1f22be72168f38c371f18639ef.webp

          多線程場景下,threadthreadTwo兩個線程執(zhí)行incr函數(shù),incr函數(shù)作為共享資源代碼段被多線程讀寫操作,我們將它稱為臨界區(qū),為了保證臨界區(qū)互斥,使用Synchronized修飾incr函數(shù)即可。

                
                public?class?SyncTest?{

          ????private?int?j?=?0;
          ????
          ????/**
          ?????*?自增方法
          ?????*/

          ????public?synchronized?void?incr(){
          ????????//臨界區(qū)代碼--start
          ????????for?(int?i?=?0;?i?<?10000;?i++)?{
          ????????????j++;
          ????????}
          ????????//臨界區(qū)代碼--end
          ????}

          ????public?int?getJ()?{
          ????????return?j;
          ????}
          }

          public?class?SyncMain?{

          ????public?static?void?main(String[]?agrs)?throws?InterruptedException?{
          ????????SyncTest?syncTest?=?new?SyncTest();
          ????????Thread?thread?=?new?Thread(()?->?syncTest.incr());
          ????????Thread?threadTwo?=?new?Thread(()?->?syncTest.incr());
          ????????thread.start();
          ????????threadTwo.start();
          ????????thread.join();
          ????????threadTwo.join();
          ????????//最終打印結(jié)果是20000,如果不使用synchronized修飾,就會導(dǎo)致線程安全問題,輸出不確定結(jié)果
          ????????System.out.println(syncTest.getJ());
          ????}

          }

          代碼十分簡單,incr函數(shù)被synchronized修飾,函數(shù)邏輯是對j進(jìn)行10000次累加,兩個線程執(zhí)行incr函數(shù),最后輸出j結(jié)果。

          synchronized修飾函數(shù)我們簡稱同步函數(shù),線程執(zhí)行稱同步函數(shù)前,需要先獲取監(jiān)視器鎖,簡稱鎖,獲取鎖成功才能執(zhí)行同步函數(shù),同步函數(shù)執(zhí)行完后,線程會釋放鎖并通知喚醒其他線程獲取鎖,獲取鎖失敗「則阻塞并等待通知喚醒該線程重新獲取鎖」,同步函數(shù)會以this作為鎖,即當(dāng)前對象,以上面的代碼段為例就是syncTest對象。

          ac56b29f9f33c14d5af4d760ff2136fa.webp
          • 線程thread執(zhí)行syncTest.incr()
          • 線程thread獲取鎖成功
          • 線程threadTwo執(zhí)行syncTest.incr()
          • 線程threadTwo獲取鎖失敗
          • 線程threadTwo阻塞并等待喚醒
          • 線程thread執(zhí)行完syncTest.incr(),j累積到10000
          • 線程thread釋放鎖,通知喚醒threadTwo線程獲取鎖
          • 線程threadTwo獲取鎖成功
          • 線程threadTwo執(zhí)行完syncTest.incr(),j累積到20000
          • 線程threadTwo釋放鎖

          靜態(tài)函數(shù)

          靜態(tài)函數(shù)顧名思義,就是靜態(tài)的函數(shù),它使用Synchronized的方式與普通函數(shù)一致,唯一的區(qū)別是鎖的對象不再是this,而是Class對象。

          1432d2cf48e34f374affd4dd84d6c4f0.webp

          多線程執(zhí)行Synchronized修飾靜態(tài)函數(shù)代碼段如下。

                
                public?class?SyncTest?{

          ????private?static?int?j?=?0;
          ????
          ????/**
          ?????*?自增方法
          ?????*/

          ????public?static?synchronized?void?incr(){
          ????????//臨界區(qū)代碼--start
          ????????for?(int?i?=?0;?i?<?10000;?i++)?{
          ????????????j++;
          ????????}
          ????????//臨界區(qū)代碼--end
          ????}

          ????public?static?int?getJ()?{
          ????????return?j;
          ????}
          }

          public?class?SyncMain?{

          ????public?static?void?main(String[]?agrs)?throws?InterruptedException?{
          ????????Thread?thread?=?new?Thread(()?->?SyncTest.incr());
          ????????Thread?threadTwo?=?new?Thread(()?->?SyncTest.incr());
          ????????thread.start();
          ????????threadTwo.start();
          ????????thread.join();
          ????????threadTwo.join();
          ????????//最終打印結(jié)果是20000,如果不使用synchronized修飾,就會導(dǎo)致線程安全問題,輸出不確定結(jié)果
          ????????System.out.println(SyncTest.getJ());
          ????}

          }

          Java的靜態(tài)資源可以直接通過類名調(diào)用,靜態(tài)資源不屬于任何實(shí)例對象,它只屬于Class對象,每個ClassJ V M中只有唯一的一個Class對象,所以同步靜態(tài)函數(shù)會以Class對象作為鎖,后續(xù)獲取鎖、釋放鎖流程都一致。

          代碼塊

          前面介紹的普通函數(shù)與靜態(tài)函數(shù)粒度都比較大,以整個函數(shù)為范圍鎖定,現(xiàn)在想把范圍縮小、靈活配置,就需要使用代碼塊了,使用{}符號定義范圍給Synchronized修飾。

          6575c79a2ab2d8e72afb3ec9b1d10c2c.webp

          下面代碼中定義了syncDbData函數(shù),syncDbData是一個偽同步數(shù)據(jù)的函數(shù),耗時2秒,并且邏輯不涉及共享資源讀寫操作非臨界區(qū)),另外還有兩個函數(shù)incrincrTwo,都是在自增邏輯前執(zhí)行了syncDbData函數(shù),只是使用Synchronized的姿勢不同,一個是修飾在函數(shù)上,另一個是修飾在代碼塊上。

                
                public?class?SyncTest?{

          ????private?static?int?j?=?0;


          ????/**
          ?????*?同步庫數(shù)據(jù),比較耗時,代碼資源不涉及共享資源讀寫操作。
          ?????*/

          ????public?void?syncDbData()?{
          ????????System.out.println("db數(shù)據(jù)開始同步------------");
          ????????try?{
          ????????????//同步時間需要2秒
          ????????????Thread.sleep(2000);
          ????????}?catch?(InterruptedException?e)?{
          ????????????e.printStackTrace();
          ????????}
          ????????System.out.println("db數(shù)據(jù)開始同步完成------------");
          ????}

          ????//自增方法
          ????public?synchronized?void?incr()?{
          ????????//start--臨界區(qū)代碼
          ????????//同步庫數(shù)據(jù)
          ????????syncDbData();
          ????????for?(int?i?=?0;?i?<?10000;?i++)?{
          ????????????j++;
          ????????}
          ????????//end--臨界區(qū)代碼
          ????}

          ????//自增方法
          ????public?void?incrTwo()?{
          ????????//同步庫數(shù)據(jù)
          ????????syncDbData();
          ????????synchronized?(this)?{
          ????????????//start--臨界區(qū)代碼
          ????????????for?(int?i?=?0;?i?<?10000;?i++)?{
          ????????????????j++;
          ????????????}
          ????????????//end--臨界區(qū)代碼
          ????????}

          ????}

          ????public?int?getJ()?{
          ????????return?j;
          ????}

          }


          public?class?SyncMain?{

          ????public?static?void?main(String[]?agrs)?throws?InterruptedException?{
          ????????//incr同步方法執(zhí)行
          ????????SyncTest?syncTest?=?new?SyncTest();
          ????????Thread?thread?=?new?Thread(()?->?syncTest.incr());
          ????????Thread?threadTwo?=?new?Thread(()?->?syncTest.incr());
          ????????thread.start();
          ????????threadTwo.start();
          ????????thread.join();
          ????????threadTwo.join();
          ????????//最終打印結(jié)果是20000
          ????????System.out.println(syncTest.getJ());

          ????????//incrTwo同步塊執(zhí)行
          ????????thread?=?new?Thread(()?->?syncTest.incrTwo());
          ????????threadTwo?=?new?Thread(()?->?syncTest.incrTwo());
          ????????thread.start();
          ????????threadTwo.start();
          ????????thread.join();
          ????????threadTwo.join();
          ????????//最終打印結(jié)果是40000
          ????????System.out.println(syncTest.getJ());
          ????}

          }

          先看看incr同步方法執(zhí)行,流程和前面沒區(qū)別,只是Synchronized鎖定的范圍太大,把syncDbData()也納入臨界區(qū)中,多線程場景執(zhí)行,會有性能上的浪費(fèi),因為syncDbData()完全可以讓多線程并行并發(fā)執(zhí)行。

          6ab6cfd68ebe49391ef709b3757ea8c4.webp

          我們通過代碼塊的方式,來縮小范圍,定義正確的臨界區(qū),提升性能,目光轉(zhuǎn)到incrTwo同步塊執(zhí)行,incrTwo函數(shù)使用修飾代碼塊的方式同步,只對自增代碼段進(jìn)行鎖定。

          be0b88ee4de6906e2efe5a3cf4e34ca9.webp

          代碼塊同步方式除了靈活控制范圍外,還能做線程間的協(xié)同工作,因為Synchronized ()括號中能接收任何對象作為鎖,所以可以通過Objectwait、notify、notifyAll等函數(shù),做多線程間的通信協(xié)同(本文不對線程通信協(xié)同做展開,主角是Synchronized,而且也不推薦去用這些方法,因為LockSupport工具類會是更好的選擇)。

          • wait:當(dāng)前線程暫停,釋放鎖
          • notify:釋放鎖,喚醒調(diào)用了wait的線程(如果有多個隨機(jī)喚醒一個)
          • notifyAll:釋放鎖,喚醒調(diào)用了wait的所有線程
          Synchronized原理
                
                ??public?class?SyncTest?{

          ????private?static?int?j?=?0;


          ????/**
          ?????*?同步庫數(shù)據(jù),比較耗時,代碼資源不涉及共享資源讀寫操作。
          ?????*/

          ????public?void?syncDbData()?{
          ????????System.out.println("db數(shù)據(jù)開始同步------------");
          ????????try?{
          ????????????//同步時間需要2秒
          ????????????Thread.sleep(2000);
          ????????}?catch?(InterruptedException?e)?{
          ????????????e.printStackTrace();
          ????????}
          ????????System.out.println("db數(shù)據(jù)開始同步完成------------");
          ????}

          ????//自增方法
          ????public?synchronized?void?incr()?{
          ????????//start--臨界區(qū)代碼
          ????????//同步庫數(shù)據(jù)
          ????????syncDbData();
          ????????for?(int?i?=?0;?i?<?10000;?i++)?{
          ????????????j++;
          ????????}
          ????????//end--臨界區(qū)代碼
          ????}

          ????//自增方法
          ????public?void?incrTwo()?{
          ????????//同步庫數(shù)據(jù)
          ????????syncDbData();
          ????????synchronized?(this)?{
          ????????????//start--臨界區(qū)代碼
          ????????????for?(int?i?=?0;?i?<?10000;?i++)?{
          ????????????????j++;
          ????????????}
          ????????????//end--臨界區(qū)代碼
          ????????}

          ????}

          ????public?int?getJ()?{
          ????????return?j;
          ????}

          }?

          為了探究Synchronized原理,我們對上面的代碼進(jìn)行反編譯,輸出反編譯后結(jié)果,看看底層是如何實(shí)現(xiàn)的(環(huán)境Java 11、win 10系統(tǒng))。

                
                ??只截取了incr與incrTwo函數(shù)內(nèi)容
          ????????
          ??public?synchronized?void?incr();
          ????Code:
          ???????0:?aload_0?????????????????????????????????????????
          ???????1:?invokevirtual?#11?????????????????//?Method?syncDbData:()V?
          ???????4:?iconst_0??????????????????????????
          ???????5:?istore_1??????????????????????????
          ???????6:?iload_1?????????????????????????????????????
          ???????7:?sipush????????10000???????????????
          ??????10:?if_icmpge?????27
          ??????13:?getstatic?????#12?????????????????//?Field?j:I
          ??????16:?iconst_1
          ??????17:?iadd
          ??????18:?putstatic?????#12?????????????????//?Field?j:I
          ??????21:?iinc??????????1,?1
          ??????24:?goto??????????6
          ??????27:?return

          ??public?void?incrTwo();????
          ????Code:
          ???????0:?aload_0
          ???????1:?invokevirtual?#11?????????????????//?Method?syncDbData:()V
          ???????4:?aload_0
          ???????5:?dup
          ???????6:?astore_1
          ???????7:?monitorenter?????????????????????//獲取鎖
          ???????8:?iconst_0
          ???????9:?istore_2
          ??????10:?iload_2
          ??????11:?sipush????????10000
          ??????14:?if_icmpge?????31
          ??????17:?getstatic?????#12?????????????????//?Field?j:I
          ??????20:?iconst_1
          ??????21:?iadd
          ??????22:?putstatic?????#12?????????????????//?Field?j:I
          ??????25:?iinc??????????2,?1
          ??????28:?goto??????????10
          ??????31:?aload_1
          ??????32:?monitorexit??????????????????????//正常退出釋放鎖?
          ??????33:?goto??????????41
          ??????36:?astore_3
          ??????37:?aload_1
          ??????38:?monitorexit??????????????????????//異步退出釋放鎖????
          ??????39:?aload_3
          ??????40:?athrow
          ??????41:?return

          ps:對上面指令感興趣的讀者,可以百度或google一下“JVM 虛擬機(jī)字節(jié)碼指令表”

          先看incrTwo函數(shù),incrTwo是代碼塊方式同步,在反編譯后的結(jié)果中,我們發(fā)現(xiàn)存在monitorentermonitorexit指令(獲取鎖、釋放鎖)。

          monitorenter指令插入到同步代碼塊的開始位置,monitorexit指令插入到同步代碼塊的結(jié)束位置,J V M需要保證每一個 monitorenter都有monitorexit與之對應(yīng)。

          任何對象都有一個監(jiān)視器鎖(monitor)關(guān)聯(lián),線程執(zhí)行monitorenter指令時嘗試獲取monitor的所有權(quán)。

          • 如果monitor的進(jìn)入數(shù)為0,則該線程進(jìn)入monitor,然后將進(jìn)入數(shù)設(shè)置為1,該線程為monitor的所有者
          • 如果線程已經(jīng)占有該monitor,重新進(jìn)入,則monitor的進(jìn)入數(shù)加1
          • 線程執(zhí)行monitorexitmonitor的進(jìn)入數(shù)-1,執(zhí)行過多少次monitorenter,最終要執(zhí)行對應(yīng)次數(shù)的monitorexit
          • 如果其他線程已經(jīng)占用monitor,則該線程進(jìn)入阻塞狀態(tài),直到monitor的進(jìn)入數(shù)為0,再重新嘗試獲取monitor的所有權(quán)

          回過頭看incr函數(shù),incr是普通函數(shù)方式同步,雖然在反編譯后的結(jié)果中沒有看到monitorentermonitorexit指令,但是實(shí)際執(zhí)行的流程與incrTwo函數(shù)一樣,通過monitor來執(zhí)行,只不過它是一種隱式的方式來實(shí)現(xiàn),最后放一張流程圖。

          b90405610ff997a898609ebbea92e07b.webpSynchronized優(yōu)化

          Jdk 1.5以后對Synchronized關(guān)鍵字做了各種的優(yōu)化,經(jīng)過優(yōu)化后Synchronized已經(jīng)變得原來越快了,這也是為什么官方建議使用Synchronized的原因,具體的優(yōu)化點(diǎn)如下。

          • 鎖粗化
          • 鎖消除
          • 鎖升級

          鎖粗化

          互斥的臨界區(qū)范圍應(yīng)該盡可能小,這樣做的目的是為了使同步的操作數(shù)量盡可能縮小,縮短阻塞時間,如果存在鎖競爭,那么等待鎖的線程也能盡快拿到鎖。

          但是加鎖解鎖也需要消耗資源,如果存在一系列的連續(xù)加鎖解鎖操作,可能會導(dǎo)致不必要的性能損耗,鎖粗化就是將「多個連續(xù)的加鎖、解鎖操作連接在一起」,擴(kuò)展成一個范圍更大的鎖,避免頻繁的加鎖解鎖操作。

          9ddeadd0f5353623a669bef61875eb9d.webp

          J V M會檢測到一連串的操作都對同一個對象加鎖(for循環(huán)10000次執(zhí)行j++,沒有鎖粗化就要進(jìn)行10000次加鎖/解鎖),此時J V M就會將加鎖的范圍粗化到這一連串操作的外部(比如for循環(huán)體外),使得這一連串操作只需要加一次鎖即可。

          鎖消除

          Java虛擬機(jī)在JIT編譯時(可以簡單理解為當(dāng)某段代碼即將第一次被執(zhí)行時進(jìn)行編譯,又稱即時編譯),通過對運(yùn)行上下文的掃描,經(jīng)過逃逸分析(對象在函數(shù)中被使用,也可能被外部函數(shù)所引用,稱為函數(shù)逃逸),去除不可能存在共享資源競爭的鎖,通過這種方式消除沒有必要的鎖,可以節(jié)省毫無意義的時間消耗。

          36b24a0a4f59ac754eee143aae39e842.webp

          代碼中使用Object作為鎖,但是Object對象的生命周期只在incrFour()函數(shù)中,并不會被其他線程所訪問到,所以在J I T編譯階段就會被優(yōu)化掉(此處的Object屬于沒有逃逸的對象)。

          鎖升級

          Java中每個對象都擁有對象頭,對象頭由Mark World 、指向類的指針、以及數(shù)組長度三部分組成,本文,我們只需要關(guān)心Mark World 即可,Mark World ?記錄了對象的HashCode、分代年齡和鎖標(biāo)志位信息。

          Mark World簡化結(jié)構(gòu)

          鎖狀態(tài) 存儲內(nèi)容 鎖標(biāo)記
          無鎖 對象的hashCode、對象分代年齡、是否是偏向鎖(0) 01
          偏向鎖 偏向線程ID、偏向時間戳、對象分代年齡、是否是偏向鎖(1) 01
          輕量級鎖 指向棧中鎖記錄的指針 00
          重量級鎖 指向互斥量(重量級鎖)的指針 10

          讀者們只需知道,鎖的升級變化,體現(xiàn)在鎖對象的對象頭Mark World部分,也就是說Mark World的內(nèi)容會隨著鎖升級而改變。

          Java1.5以后為了減少獲取鎖和釋放鎖帶來的性能消耗,引入了偏向鎖輕量級鎖,Synchronized的升級順序是 「無鎖-->偏向鎖-->輕量級鎖-->重量級鎖,只會升級不會降級

          偏向鎖

          在大多數(shù)情況下,鎖總是由同一線程多次獲得,不存在多線程競爭,所以出現(xiàn)了偏向鎖,其目標(biāo)就是在只有一個線程執(zhí)行同步代碼塊時,降低獲取鎖帶來的消耗,提高性能(可以通過J V M參數(shù)關(guān)閉偏向鎖:-XX:-UseBiasedLocking=false,關(guān)閉之后程序默認(rèn)會進(jìn)入輕量級鎖狀態(tài))。

          線程執(zhí)行同步代碼或方法前,線程只需要判斷對象頭的Mark Word中線程ID與當(dāng)前線程ID是否一致,如果一致直接執(zhí)行同步代碼或方法,具體流程如下

          3e996e1f06015ba28bdf85ebf2b118a2.webp
          • 無鎖狀態(tài),存儲內(nèi)容「是否為偏向鎖(0)」,鎖標(biāo)識位01
            • CAS設(shè)置當(dāng)前線程ID到Mark Word存儲內(nèi)容中
            • 是否為偏向鎖0 => 是否為偏向鎖1
            • 執(zhí)行同步代碼或方法
          • 偏向鎖狀態(tài),存儲內(nèi)容「是否為偏向鎖(1)、線程ID」,鎖標(biāo)識位01
            • 對比線程ID是否一致,如果一致執(zhí)行同步代碼或方法,否則進(jìn)入下面的流程
            • 如果不一致,CASMark Word的線程ID設(shè)置為當(dāng)前線程ID,設(shè)置成功,執(zhí)行同步代碼或方法,否則進(jìn)入下面的流程
            • CAS設(shè)置失敗,證明存在多線程競爭情況,觸發(fā)撤銷偏向鎖,當(dāng)?shù)竭_(dá)全局安全點(diǎn),偏向鎖的線程被掛起,偏向鎖升級為輕量級鎖,然后在安全點(diǎn)的位置恢復(fù)繼續(xù)往下執(zhí)行。

          輕量級鎖

          輕量級鎖考慮的是競爭鎖對象的線程不多,持有鎖時間也不長的場景。因為阻塞線程需要C P U從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),代價較大,如果剛剛阻塞不久這個鎖就被釋放了,那這個代價就有點(diǎn)得不償失,所以干脆不阻塞這個線程,讓它自旋一段時間等待鎖釋放。

          當(dāng)前線程持有的鎖是偏向鎖的時候,被另外的線程所訪問,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,從而提高性能。輕量級鎖的獲取主要有兩種情況:① 當(dāng)關(guān)閉偏向鎖功能時;② 多個線程競爭偏向鎖導(dǎo)致偏向鎖升級為輕量級鎖。

          6f49ce80ee70a46509545711dea4fa5f.webp
          • 無鎖狀態(tài),存儲內(nèi)容「是否為偏向鎖(0)」,鎖標(biāo)識位01
            • 關(guān)閉偏向鎖功能時
            • CAS設(shè)置當(dāng)前線程棧中鎖記錄的指針到Mark Word存儲內(nèi)容
            • 鎖標(biāo)識位設(shè)置為00
            • 執(zhí)行同步代碼或方法
            • 釋放鎖時,還原來Mark Word內(nèi)容
          • 輕量級鎖狀態(tài),存儲內(nèi)容「線程棧中鎖記錄的指針」,鎖標(biāo)識位00(存儲內(nèi)容的線程是指"持有輕量級鎖的線程")
            • CAS設(shè)置當(dāng)前線程棧中鎖記錄的指針到Mark Word存儲內(nèi)容,設(shè)置成功獲取輕量級鎖,執(zhí)行同步塊代碼或方法,否則執(zhí)行下面的邏輯
            • 設(shè)置失敗,證明多線程存在一定競爭,線程自旋上一步的操作,自旋一定次數(shù)后還是失敗,輕量級鎖升級為重量級鎖
            • Mark Word存儲內(nèi)容替換成重量級鎖指針,鎖標(biāo)記位10

          重量級鎖

          輕量級鎖膨脹之后,就升級為重量級鎖,重量級鎖是依賴操作系統(tǒng)的MutexLock互斥鎖)來實(shí)現(xiàn)的,需要從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),這個成本非常高,這就是為什么Java1.6之前Synchronized效率低的原因。

          升級為重量級鎖時,鎖標(biāo)志位的狀態(tài)值變?yōu)?code style="font-size:14px;background-color:rgba(27,31,35,.05);font-family:'Operator Mono', Consolas, Monaco, Menlo, monospace;color:rgb(255,100,65);">10,此時Mark Word中存儲內(nèi)容的是重量級鎖的指針,等待鎖的線程都會進(jìn)入阻塞狀態(tài),下面是簡化版的鎖升級過程。

          3da9f05c222a5051ff42afb1ceaba561.webp歷史好文推薦 a34ebc8e02d85c25bdf40991b512e96f.webp

          非常感謝各位小哥哥小姐姐們能看到這里,原創(chuàng)不易,文章有幫助可以關(guān)注、點(diǎn)個贊、分享與評論,都是支持(莫要白嫖)!

          愿你我都能奔赴在各自想去的路上,我們下篇文章見。?

          瀏覽 49
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  男人先锋资源 | 91色逼 | 超级毛片操逼 | 91在线精品无码秘 入口APP | 99中文字幕在线观看 |