天天看點

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized

Java中的鎖可以分為隐式鎖和顯示鎖,Lock接口的鎖都是顯示鎖。JVM内置鎖就是隐式鎖,synchronized就是隐式的鎖。

顯示鎖:需要手動釋放鎖,可以設定是否為公平鎖

隐式鎖:不需要手動釋放鎖,非公平鎖

Monitor

Lock接口實作的鎖底層是通過AQS同步隊列實作的。用到了unsafe.park()方法。synchronized 底層有一個monitor螢幕,會監控持有鎖的對象。如下圖:

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized
monitorenter表示目前程式将進入同步塊              monitorexit表示即将退出同步塊,并且釋放鎖
           

那麼JVM怎麼知道我目前的對象是否已經加鎖了呢。

synchronized (object) {
    //代碼邏輯
}
           

如上圖,Monitor調用Enter方法進入監視區,它會監視object對象裡面是否有鎖标記,如果沒有就給object加上鎖标記,并執行後面的邏輯,最後釋放鎖,取消object的鎖标記。Monitor.Exit退出監視區,并釋放鎖。

鎖Monitor.Enter進入後,發現對象object上面已經有鎖标記了,那麼傳回Monitor.Enter失敗,并退出Monitor。之後再循環重試。

對象頭

鎖标記儲存在對象頭(方法區的類資訊)中的Mark Word中。

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized

鎖更新

由于JDK的優化,synchronized鎖有一個更新,極大的提升了鎖的性能。

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized

鎖對象剛建立時,對象頭裡面是無鎖的狀态,當第一個線程進來時。鎖更新為偏向鎖;當第二個線程進來,更新為輕量級鎖;第三個線程進來,等待搶鎖,第四個,第五個線程進來也是等待争搶鎖。争搶的線程變多了,鎖就會更新為重量級鎖。

無鎖

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized

無鎖态時 Mark Word 标記位為01,是否偏向标記為0。

偏向鎖

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized

此時是否偏向标記為1。

輕量級鎖

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized

鎖标志位

Java鎖-synchronized底層原理Monitor對象頭鎖更新無鎖偏向鎖輕量級鎖鎖标志位重量級鎖Lock 與synchronized

重量級鎖

更新為重量級鎖時,線程會有從使用者态到核心态的切換,是以說,大量線程搶鎖時,性能不是很好,建議使用Lock接口實作的鎖。

注意,以上兩種鎖都是單機的鎖,現在的系統都是分布式的,需要分布式鎖。可以用zookeeper或redis實作。市面上已經有成熟的分布式鎖架構。像Redisson,Curator等都很不錯。

Lock 與synchronized

(1)synchronized不會導緻死鎖現象發生;而Lock可能造成死鎖現象Lock可以讓等待。

(2)鎖的線程響應中斷,而synchronized卻不行。 

(3)通過Lock可以知道有沒有成功擷取鎖,而synchronized卻無法辦到 。

(4)Lock可以提高多個線程進行讀操作的效率 。

(5)性能上,競争不激烈兩者差不多;非常激烈時(即有大量線程同時競争)                  Lock遠遠優于synchronized。是以說,在具體使用時要根據适當情況選擇。