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

java中synchronized鎖的升級(jí)過程

 更新時(shí)間:2021年09月13日 11:24:48   作者:NetWhite  
這篇文章主要介紹了java中synchronized鎖的升級(jí)過程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

synchronized鎖的升級(jí)(偏向鎖、輕量級(jí)鎖及重量級(jí)鎖)

java同步鎖前置知識(shí)點(diǎn)

  • 1.編碼中如果使用鎖可以使用synchronized關(guān)鍵字,對(duì)方法、代碼塊進(jìn)行同步加鎖
  • 2.Synchronized同步鎖是jvm內(nèi)置的隱式鎖(相對(duì)Lock,隱式加鎖與釋放)
  • 3.Synchronized同步鎖的實(shí)現(xiàn)依賴于操作系統(tǒng),獲取鎖與釋放鎖進(jìn)行系統(tǒng)調(diào)用,會(huì)引起用戶態(tài)與內(nèi)核態(tài)切換
  • 4.jdk1.5之前加鎖只能使用synchronized,1.6引入Lock同步鎖(請(qǐng)求鎖基于java實(shí)現(xiàn),顯式加鎖與釋放、性能更優(yōu))
  • 5.jdk1.6對(duì)于Synchronzied同步鎖提出了偏向鎖、輕量級(jí)鎖、重量級(jí)鎖的概念(其實(shí)是對(duì)synchronized的性能優(yōu)化,盡可能減少鎖競(jìng)爭(zhēng)帶來的上下文切換)
  • 6.無論是使用synchronized還是Lock,線程上下文切換都是無法避免的
  • 7.Lock相對(duì)synchronized的性能優(yōu)化的其中一點(diǎn)是:在線程阻塞的時(shí)候,Lock獲取鎖不會(huì)導(dǎo)致用戶態(tài)與內(nèi)核態(tài)的切換,而synchronized會(huì)(看第3點(diǎn))。但是線程阻塞都會(huì)導(dǎo)致上下文切換(看第6點(diǎn))
  • 8.java線程的阻塞與喚醒依賴操作系統(tǒng)調(diào)用,導(dǎo)致用戶態(tài)與內(nèi)核態(tài)切換
  • 9.前面說的用戶態(tài)與內(nèi)核態(tài)切換發(fā)生的是進(jìn)程上下文切換而非線程上下文切換

本文主要關(guān)注synchronized鎖的升級(jí)。

synchronized同步鎖

java對(duì)象頭

每個(gè)java對(duì)象都有一個(gè)對(duì)象頭,對(duì)象頭由類型指針和標(biāo)記字段組成。

在64位虛擬機(jī)中,未開啟壓縮指針,標(biāo)記字段占64位,類型指針占64位,共計(jì)16個(gè)字節(jié)。

鎖類型信息為標(biāo)記字段的最后2位:00表示輕量級(jí)鎖,01表示無鎖或偏向鎖,10表示重量級(jí)鎖;如果倒數(shù)第3位為1表示這個(gè)類的偏向鎖啟用,為0表示類的偏向鎖被禁用。

如下圖,圖片來源wiki

左側(cè)一列表示偏向鎖啟用(方框1),右側(cè)一列表示偏向鎖禁用(方框3)。1和3都表示無鎖的初始狀態(tài),如果啟用偏向鎖,鎖升級(jí)的步驟應(yīng)該是1->2->4->5,如果禁用偏向鎖,鎖升級(jí)步驟是3->4->5。

我用的jdk8,打印了參數(shù)看了下,默認(rèn)是啟用偏向鎖,如要是禁用: -XX:-UseBiasedLocking

關(guān)于偏向鎖還有另外幾個(gè)參數(shù):

注意BiasedLockingStartupDelay參數(shù),默認(rèn)值4000ms,表示虛擬機(jī)啟動(dòng)的延遲4s才會(huì)使用偏向鎖(先使用輕量級(jí)鎖)。

偏向鎖

偏向鎖處理的場(chǎng)景是大部分時(shí)間只有同一條線程在請(qǐng)求鎖,沒有多線程競(jìng)爭(zhēng)鎖的情況??磳?duì)象頭圖的紅框2,有個(gè)thread ID字段:當(dāng)?shù)谝淮尉€程加鎖的時(shí)候,jvm通過cas將當(dāng)前線程地址設(shè)置到thread ID標(biāo)記位,最后3位是101。下次同一線程再獲取鎖的時(shí)候只用檢查最后3位是否為101,是否為當(dāng)前線程,epoch是否和鎖對(duì)象的類的epoch相等(wiki上說沒有再次cas設(shè)置是為了針對(duì)現(xiàn)在多處理器上的cas操作的優(yōu)化)。

偏向鎖優(yōu)化帶來的性能提升指的是避免了獲取鎖進(jìn)行系統(tǒng)調(diào)用導(dǎo)致的用戶態(tài)和內(nèi)核態(tài)的切換,因?yàn)槎际峭粭l線程獲取鎖,沒有必要每次獲取鎖的時(shí)候都要進(jìn)行系統(tǒng)調(diào)用。

如果當(dāng)前線程獲取鎖的時(shí)候(無鎖狀態(tài)下)線程ID與當(dāng)前線程不匹配,會(huì)將偏向鎖撤銷,重新偏向當(dāng)前線程,如果次數(shù)達(dá)到BiasedLockingBulkRebiasThreshold的值,默認(rèn)20次,當(dāng)前類的偏向鎖失效,影響就是epoch的值變動(dòng),加鎖類的epoch值加1,后續(xù)鎖對(duì)象會(huì)重新copy類的epoch值到圖中的epoch標(biāo)記位。如果總撤銷次數(shù)達(dá)到BiasedLockingBulkRevokeThreshold的值(默認(rèn)40次),就禁用當(dāng)前類的偏向鎖了,就是對(duì)象頭右側(cè)列了,加鎖直接從輕量鎖開始了(鎖升級(jí)了)。

偏向鎖的撤銷是個(gè)很麻煩的過程,需要所有線程達(dá)到安全點(diǎn)(發(fā)生STW),遍歷所有線程的線程棧檢查是否持有鎖對(duì)象,避免丟鎖,還有就是對(duì)epoch的處理。

如果存在多線程競(jìng)爭(zhēng),那偏向鎖就要升級(jí)了,升級(jí)到輕量級(jí)鎖。

輕量級(jí)鎖

輕量級(jí)鎖處理的場(chǎng)景是在同的時(shí)間段有不同的線程請(qǐng)求鎖(線程交替執(zhí)行)。即使同一時(shí)間段,存在多條線程競(jìng)爭(zhēng)鎖,獲取到鎖的線程持有鎖的時(shí)間也特別短,很快就釋放鎖了。

線程加鎖的時(shí)候,判斷不是重量級(jí)鎖,就會(huì)在當(dāng)前線程棧內(nèi)開辟一個(gè)空間,作為鎖記錄,將鎖對(duì)象頭的標(biāo)記字段復(fù)制過來(復(fù)制過來是做一個(gè)記錄,因?yàn)楹竺嬉焰i對(duì)象頭的標(biāo)記字段的值替換為剛才復(fù)制這個(gè)標(biāo)記字段的空間地址,就像對(duì)象頭那個(gè)圖片中的pointer to lock record部分,至于最后2位,因?yàn)槭莾?nèi)存對(duì)齊的緣故,所以是00)。然后基于CAS操作將復(fù)制這個(gè)標(biāo)記字段的地址設(shè)置為鎖對(duì)象頭的標(biāo)記位的值,如果成功就是獲取到鎖了。如果加鎖的時(shí)候判斷不是重量級(jí)鎖,最后兩位也不是01(從偏向鎖或無鎖狀態(tài)過來的),那就說明已經(jīng)有線程持有了,如果是當(dāng)前線程在(需要重入),那就設(shè)置一個(gè)0,這里是個(gè)棧結(jié)構(gòu),直接壓入一個(gè)0即可。最后釋放鎖的時(shí)候,出棧,最后一個(gè)元素記錄的就是鎖對(duì)象原來的標(biāo)記字段的值,再通過CAS設(shè)置到鎖對(duì)象頭即可。

注意在獲取鎖的時(shí)候,cas失敗,當(dāng)前線程會(huì)自旋一會(huì),達(dá)到一定次數(shù),升級(jí)到重量級(jí)鎖,當(dāng)前線程也會(huì)阻塞。

重量級(jí)鎖

重量級(jí)就是我們平常說的加的同步鎖,也就是java基礎(chǔ)的鎖實(shí)現(xiàn),獲取鎖與釋放鎖的時(shí)候都要進(jìn)行系統(tǒng)調(diào)用,從而導(dǎo)致上下文切換。

關(guān)于自旋鎖

關(guān)于自旋鎖,我查閱相關(guān)資料,主要有兩種說明:

1、是輕量級(jí)鎖競(jìng)爭(zhēng)失敗,不會(huì)立即膨脹為重量級(jí)而是先自旋一定次數(shù)嘗試獲取鎖;

2、是重量級(jí)鎖競(jìng)爭(zhēng)失敗也不會(huì)立即阻塞,也是自旋一定次數(shù)(這里涉及到一個(gè)自調(diào)整算法)。

關(guān)于這個(gè)說明,還是要看jvm的源碼實(shí)現(xiàn)才能確定哪個(gè)是真實(shí)的:

打印偏向鎖的參數(shù)

如下:

-XX:+UnlockDiagnosticVMOptions

-XX:+PrintBiasedLockingStatistics

我在main方法循環(huán)獲取同一把鎖,打印結(jié)果如下:

    public static void main(String[] args) {
        int num = 0;
        for (int i = 0; i < 1_000_000000; i++) {
            synchronized (lock) {
                num++;
            }
        }
    }

synchronized原理解析

一:synchronized原理解析

1:對(duì)象頭

首先,我們要知道對(duì)象在內(nèi)存中的布局:

已知對(duì)象是存放在堆內(nèi)存中的,對(duì)象大致可以分為三個(gè)部分,分別是對(duì)象頭、實(shí)例變量和填充字節(jié)。

  • 對(duì)象頭zhuyao是由MarkWord和Klass Point(類型指針)組成,其中Klass Point是對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個(gè)指針來確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例,Mark Word用于存儲(chǔ)對(duì)象自身的運(yùn)行時(shí)數(shù)據(jù)。如果對(duì)象是數(shù)組對(duì)象,那么對(duì)象頭占用3個(gè)字寬(Word),如果對(duì)象是非數(shù)組對(duì)象,那么對(duì)象頭占用2個(gè)字寬。(1word = 2 Byte = 16 bit)。
  • 實(shí)例變量存儲(chǔ)的是對(duì)象的屬性信息,包括父類的屬性信息,按照4字節(jié)對(duì)齊。
  • 填充字符,因?yàn)樘摂M機(jī)要求對(duì)象字節(jié)必須是8字節(jié)的整數(shù)倍,填充字符就是用于湊齊這個(gè)整數(shù)倍的。

對(duì)象頭示例

通過第一部分可以知道,Synchronized不論是修飾方法還是代碼塊,都是通過持有修飾對(duì)象的鎖來實(shí)現(xiàn)同步,那么Synchronized鎖對(duì)象是存在哪里的呢?答案是存在鎖對(duì)象的對(duì)象頭的MarkWord中。那么MarkWord在對(duì)象頭中到底長什么樣,也就是它到底存儲(chǔ)了什么呢?

在32位的虛擬機(jī)中:

在64位的虛擬機(jī)中:

上圖中的偏向鎖和輕量級(jí)鎖都是在java6以后對(duì)鎖機(jī)制進(jìn)行優(yōu)化時(shí)引進(jìn)的,下文的鎖升級(jí)部分會(huì)具體講解,Synchronized關(guān)鍵字對(duì)應(yīng)的是重量級(jí)鎖,接下來對(duì)重量級(jí)鎖在Hotspot JVM中的實(shí)現(xiàn)鎖講解。

2:Synchronized在JVM中的實(shí)現(xiàn)原理

重量級(jí)鎖對(duì)應(yīng)的鎖標(biāo)志位是10,存儲(chǔ)了指向重量級(jí)監(jiān)視器鎖的指針,在Hotspot中,對(duì)象的監(jiān)視器(monitor)鎖對(duì)象由ObjectMonitor對(duì)象實(shí)現(xiàn)(C++),其跟同步相關(guān)的數(shù)據(jù)結(jié)構(gòu)如下:

ObjectMonitor() {
    _count        = 0; //用來記錄該對(duì)象被線程獲取鎖的次數(shù)
    _waiters      = 0;
    _recursions   = 0; //鎖的重入次數(shù)
    _owner        = NULL; //指向持有ObjectMonitor對(duì)象的線程 
    _WaitSet      = NULL; //處于wait狀態(tài)的線程,會(huì)被加入到_WaitSet
    _WaitSetLock  = 0 ;
    _EntryList    = NULL ; //處于等待鎖block狀態(tài)的線程,會(huì)被加入到該列表
  }

光看這些數(shù)據(jù)結(jié)構(gòu)對(duì)監(jiān)視器鎖的工作機(jī)制還是一頭霧水,那么我們首先看一下線程在獲取鎖的幾個(gè)狀態(tài)的轉(zhuǎn)換:

線程的生命周期存在5個(gè)狀態(tài),start、running、waiting、blocking和dead

對(duì)于一個(gè)synchronized修飾的方法(代碼塊)來說:

  • 當(dāng)多個(gè)線程同時(shí)訪問該方法,那么這些線程會(huì)先被放進(jìn)_EntryList隊(duì)列,此時(shí)線程處于blocking狀態(tài)。
  • 當(dāng)一個(gè)線程獲取到了實(shí)例對(duì)象的監(jiān)視器(monitor)鎖,那么就可以進(jìn)入running狀態(tài),執(zhí)行方法,此時(shí),ObjectMonitor對(duì)象的_owner指向當(dāng)前線程,_count加1表示當(dāng)前對(duì)象鎖被一個(gè)線程獲取
  • 當(dāng)running狀態(tài)的線程調(diào)用wait()方法,那么當(dāng)前線程釋放monitor對(duì)象,進(jìn)入waiting狀態(tài),ObjectMonitor對(duì)象的_owner變?yōu)閚ull,_count減1,同時(shí)線程進(jìn)入_WaitSet隊(duì)列,直到有線程調(diào)用notify()方法喚醒該線程,則該線程重新獲取monitor對(duì)象進(jìn)入_Owner區(qū)
  • 如果當(dāng)前線程執(zhí)行完畢,那么也釋放monitor對(duì)象,進(jìn)入waiting狀態(tài),ObjectMonitor對(duì)象的_owner變?yōu)閚ull,_count減1

那么Synchronized修飾的代碼塊/方法如何獲取monitor對(duì)象的呢?

在JVM規(guī)范里可以看到,不管是方法同步還是代碼塊同步都是基于進(jìn)入和退出monitor對(duì)象來實(shí)現(xiàn),然而二者在具體實(shí)現(xiàn)上又存在很大的區(qū)別。通過javap對(duì)class字節(jié)碼文件反編譯可以得到反編譯后的代碼。

(1)Synchronized修飾代碼塊:

Synchronized代碼塊同步在需要同步的代碼塊開始的位置插入monitorentry指令,在同步結(jié)束的位置或者異常出現(xiàn)的位置插入monitorexit指令;JVM要保證monitorentry和monitorexit都是成對(duì)出現(xiàn)的,任何對(duì)象都有一個(gè)monitor與之對(duì)應(yīng),當(dāng)這個(gè)對(duì)象的monitor被持有以后,它將處于鎖定狀態(tài)。

例如,同步代碼塊如下:

public class SyncCodeBlock {
   public int i;
   public void syncTask(){
       synchronized (this){
           i++;
       }
   }
}

對(duì)同步代碼塊編譯后的class字節(jié)碼文件反編譯,結(jié)果如下(僅保留方法部分的反編譯內(nèi)容):

  public void syncTask();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=3, args_size=1
         0: aload_0
         1: dup
         2: astore_1
         3: monitorenter  //注意此處,進(jìn)入同步方法
         4: aload_0
         5: dup
         6: getfield      #2             // Field i:I
         9: iconst_1
        10: iadd
        11: putfield      #2            // Field i:I
        14: aload_1
        15: monitorexit   //注意此處,退出同步方法
        16: goto          24
        19: astore_2
        20: aload_1
        21: monitorexit //注意此處,退出同步方法
        22: aload_2
        23: athrow
        24: return
      Exception table:
      //省略其他字節(jié)碼.......

可以看出同步方法塊在進(jìn)入代碼塊時(shí)插入了monitorentry語句,在退出代碼塊時(shí)插入了monitorexit語句,為了保證不論是正常執(zhí)行完畢(第15行)還是異常跳出代碼塊(第21行)都能執(zhí)行monitorexit語句,因此會(huì)出現(xiàn)兩句monitorexit語句。

(2)Synchronized修飾方法:

Synchronized方法同步不再是通過插入monitorentry和monitorexit指令實(shí)現(xiàn),而是由方法調(diào)用指令來讀取運(yùn)行時(shí)常量池中的ACC_SYNCHRONIZED標(biāo)志隱式實(shí)現(xiàn)的,如果方法表結(jié)構(gòu)(method_info Structure)中的ACC_SYNCHRONIZED標(biāo)志被設(shè)置,那么線程在執(zhí)行方法前會(huì)先去獲取對(duì)象的monitor對(duì)象,如果獲取成功則執(zhí)行方法代碼,執(zhí)行完畢后釋放monitor對(duì)象,如果monitor對(duì)象已經(jīng)被其它線程獲取,那么當(dāng)前線程被阻塞。

同步方法代碼如下:

public class SyncMethod {
   public int i;
   public synchronized void syncTask(){
           i++;
   }
}

對(duì)同步方法編譯后的class字節(jié)碼反編譯,結(jié)果如下(僅保留方法部分的反編譯內(nèi)容):

public synchronized void syncTask();
    descriptor: ()V
    //方法標(biāo)識(shí)ACC_PUBLIC代表public修飾,ACC_SYNCHRONIZED指明該方法為同步方法
    flags: ACC_PUBLIC, ACC_SYNCHRONIZED
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #2                  // Field i:I
         5: iconst_1
         6: iadd
         7: putfield      #2                  // Field i:I
        10: return
      LineNumberTable:
        line 12: 0
        line 13: 10
}

可以看出方法開始和結(jié)束的地方都沒有出現(xiàn)monitorentry和monitorexit指令,但是出現(xiàn)的ACC_SYNCHRONIZED標(biāo)志位。

三、鎖的優(yōu)化

1、鎖升級(jí)

鎖的4中狀態(tài):無鎖狀態(tài)、偏向鎖狀態(tài)、輕量級(jí)鎖狀態(tài)、重量級(jí)鎖狀態(tài)(級(jí)別從低到高)

(1)偏向鎖:

為什么要引入偏向鎖?

  • 因?yàn)榻?jīng)過HotSpot的作者大量的研究發(fā)現(xiàn),大多數(shù)時(shí)候是不存在鎖競(jìng)爭(zhēng)的,常常是一個(gè)線程多次獲得同一個(gè)鎖,因此如果每次都要競(jìng)爭(zhēng)鎖會(huì)增大很多沒有必要付出的代價(jià),為了降低獲取鎖的代價(jià),才引入的偏向鎖。

偏向鎖的升級(jí):

  • 當(dāng)線程1訪問代碼塊并獲取鎖對(duì)象時(shí),會(huì)在java對(duì)象頭和棧幀中記錄偏向的鎖的threadID,因?yàn)槠蜴i不會(huì)主動(dòng)釋放鎖,因此以后線程1再次獲取鎖的時(shí)候,需要比較當(dāng)前線程的threadID和Java對(duì)象頭中的threadID是否一致,如果一致(還是線程1獲取鎖對(duì)象),則無需使用CAS來加鎖、解鎖;如果不一致(其他線程,如線程2要競(jìng)爭(zhēng)鎖對(duì)象,而偏向鎖不會(huì)主動(dòng)釋放因此還是存儲(chǔ)的線程1的threadID),那么需要查看Java對(duì)象頭中記錄的線程1是否存活,如果沒有存活,那么鎖對(duì)象被重置為無鎖狀態(tài),其它線程(線程2)可以競(jìng)爭(zhēng)將其設(shè)置為偏向鎖;如果存活,那么立刻查找該線程(線程1)的棧幀信息,如果還是需要繼續(xù)持有這個(gè)鎖對(duì)象,那么暫停當(dāng)前線程1,撤銷偏向鎖,升級(jí)為輕量級(jí)鎖,如果線程1 不再使用該鎖對(duì)象,那么將鎖對(duì)象狀態(tài)設(shè)為無鎖狀態(tài),重新偏向新的線程。

偏向鎖的取消:

  • 偏向鎖是默認(rèn)開啟的,而且開始時(shí)間一般是比應(yīng)用程序啟動(dòng)慢幾秒,如果不想有這個(gè)延遲,那么可以使用-XX:BiasedLockingStartUpDelay=0;
  • 如果不想要偏向鎖,那么可以通過-XX:-UseBiasedLocking = false來設(shè)置;

(2)輕量級(jí)鎖

為什么要引入輕量級(jí)鎖?

  • 輕量級(jí)鎖考慮的是競(jìng)爭(zhēng)鎖對(duì)象的線程不多,而且線程持有鎖的時(shí)間也不長的情景。因?yàn)樽枞€程需要CPU從用戶態(tài)轉(zhuǎn)到內(nèi)核態(tài),代價(jià)較大,如果剛剛阻塞不久這個(gè)鎖就被釋放了,那這個(gè)代價(jià)就有點(diǎn)得不償失了,因此這個(gè)時(shí)候就干脆不阻塞這個(gè)線程,讓它自旋這等待鎖釋放。

輕量級(jí)鎖什么時(shí)候升級(jí)為重量級(jí)鎖?

  • 線程1獲取輕量級(jí)鎖時(shí)會(huì)先把鎖對(duì)象的對(duì)象頭MarkWord復(fù)制一份到線程1的棧幀中創(chuàng)建的用于存儲(chǔ)鎖記錄的空間(稱為DisplacedMarkWord),然后使用CAS把對(duì)象頭中的內(nèi)容替換為線程1存儲(chǔ)的鎖記錄(DisplacedMarkWord)的地址;
  • 如果在線程1復(fù)制對(duì)象頭的同時(shí)(在線程1CAS之前),線程2也準(zhǔn)備獲取鎖,復(fù)制了對(duì)象頭到線程2的鎖記錄空間中,但是在線程2CAS的時(shí)候,發(fā)現(xiàn)線程1已經(jīng)把對(duì)象頭換了,線程2的CAS失敗,那么線程2就嘗試使用自旋鎖來等待線程1釋放鎖。
  • 但是如果自旋的時(shí)間太長也不行,因?yàn)樽孕且腃PU的,因此自旋的次數(shù)是有限制的,比如10次或者100次,如果自旋次數(shù)到了線程1還沒有釋放鎖,或者線程1還在執(zhí)行,線程2還在自旋等待,這時(shí)又有一個(gè)線程3過來競(jìng)爭(zhēng)這個(gè)鎖對(duì)象,那么這個(gè)時(shí)候輕量級(jí)鎖就會(huì)膨脹為重量級(jí)鎖。重量級(jí)鎖把除了擁有鎖的線程都阻塞,防止CPU空轉(zhuǎn)。

注意:為了避免無用的自旋,輕量級(jí)鎖一旦膨脹為重量級(jí)鎖就不會(huì)再降級(jí)為輕量級(jí)鎖了;偏向鎖升級(jí)為輕量級(jí)鎖也不能再降級(jí)為偏向鎖。一句話就是鎖可以升級(jí)不可以降級(jí),但是偏向鎖狀態(tài)可以被重置為無鎖狀態(tài)。

(3)這幾種鎖的優(yōu)缺點(diǎn)(偏向鎖、輕量級(jí)鎖、重量級(jí)鎖)

2、鎖粗化

  • 按理來說,同步塊的作用范圍應(yīng)該盡可能小,僅在共享數(shù)據(jù)的實(shí)際作用域中才進(jìn)行同步,這樣做的目的是為了使需要同步的操作數(shù)量盡可能縮小,縮短阻塞時(shí)間,如果存在鎖競(jìng)爭(zhēng),那么等待鎖的線程也能盡快拿到鎖。
  • 但是加鎖解鎖也需要消耗資源,如果存在一系列的連續(xù)加鎖解鎖操作,可能會(huì)導(dǎo)致不必要的性能損耗。
  • 鎖粗化就是將多個(gè)連續(xù)的加鎖、解鎖操作連接在一起,擴(kuò)展成一個(gè)范圍更大的鎖,避免頻繁的加鎖解鎖操作。

3、鎖消除

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

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Java IO復(fù)用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java IO復(fù)用_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    這篇文章主要介紹了Java IO復(fù)用的相關(guān)知識(shí),非常不錯(cuò),具有參考借鑒價(jià)值,需要的的朋友參考下吧
    2017-05-05
  • 詳解Mybatis模板(已優(yōu)化)適合小白

    詳解Mybatis模板(已優(yōu)化)適合小白

    這篇文章主要介紹了Mybatis模板(已優(yōu)化)適合小白,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • Java 處理圖片與base64 編碼的相互轉(zhuǎn)換的示例

    Java 處理圖片與base64 編碼的相互轉(zhuǎn)換的示例

    本篇文章主要介紹了Java 處理圖片與base64 編碼的相互轉(zhuǎn)換的示例,具有一定的參考價(jià)值,有興趣的可以了解一下
    2017-08-08
  • 關(guān)于junit單元測(cè)試@Test的使用方式

    關(guān)于junit單元測(cè)試@Test的使用方式

    這篇文章主要介紹了關(guān)于junit單元測(cè)試@Test的使用方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • 為什么在foreach循環(huán)中JAVA集合不能添加或刪除元素

    為什么在foreach循環(huán)中JAVA集合不能添加或刪除元素

    今天給大家?guī)淼奈恼率顷P(guān)于Java的相關(guān)知識(shí),文章圍繞著為什么在foreach循環(huán)中JAVA集合不能添加或刪除元素展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • IDEA 工程里 new不出來Vue文件的圖文解決方案

    IDEA 工程里 new不出來Vue文件的圖文解決方案

    這篇文章主要介紹了IDEA 工程里 new不出來Vue文件的解決方案,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • SpringBoot和Swagger結(jié)合提高API開發(fā)效率

    SpringBoot和Swagger結(jié)合提高API開發(fā)效率

    這篇文章主要介紹了SpringBoot和Swagger結(jié)合提高API開發(fā)效率的相關(guān)資料,需要的朋友可以參考下
    2017-09-09
  • Java面試必備之AQS阻塞隊(duì)列和條件隊(duì)列

    Java面試必備之AQS阻塞隊(duì)列和條件隊(duì)列

    我們大概知道AQS就是一個(gè)框架,把很多功能都給實(shí)現(xiàn)了(比如入隊(duì)規(guī)則,喚醒節(jié)點(diǎn)中的線程等),我們?nèi)绻褂玫脑捴恍枰獙?shí)現(xiàn)其中的一些方法(比如tryAcquire等)就行了!這次主要說說AQS中阻塞隊(duì)列的的入隊(duì)規(guī)則還有條件變量,需要的朋友可以參考下
    2021-06-06
  • SpringBoot中修改依賴版本的方法

    SpringBoot中修改依賴版本的方法

    這篇文章主要介紹了SpringBoot中如何修改依賴的版本,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-08-08
  • springboot yml中profiles的巧妙用法(小白必看多環(huán)境配置)

    springboot yml中profiles的巧妙用法(小白必看多環(huán)境配置)

    這篇文章主要介紹了springboot yml中profiles的巧妙用法,非常適合多環(huán)境配置場(chǎng)景,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-04-04

最新評(píng)論