偏向鎖、輕量級鎖、重量級鎖升級過程中的疑問解答

1 背景

在https://blog.csdn.net/qq_33996921/article/details/106629770這篇文章《Synchronized關鍵字和鎖升級(偏向鎖、輕量級鎖、重量級鎖)》中講解了Synchronized使用原理,及鎖的升級,在翻閱資料以及看別的博客中一些讀者遇到的疑問,本文主要針對在鎖升級中的一些問題進行解釋。

2 鎖升級的流程圖

先從《併發編程的藝術》這本書中摘抄了兩個鎖升級的圖:

1、偏向鎖的獲得和撤銷流程

[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-Jcraaem2-1592059245925)(S:\01_學習文檔\B_csdn\07_concurrent\圖片\偏向鎖.png)]

2、輕量級鎖及膨脹流程

在這裏插入圖片描述

以上鎖的過程不做詳細的贅述,在上一篇提到的文章中已做了詳細描述,下面針對一些疑問做相應的解答。

3、鎖對象頭

對象頭的信息:

在這裏插入圖片描述

對象 MarkWord 狀態以不同方式轉換的過程如下:

在這裏插入圖片描述

翻譯一下:

在這裏插入圖片描述

4 鎖升級中的問題

1、問題當線程A 獲取了偏向鎖,此線程B進來了,走到了同步代碼塊前,此時是的鎖是如何變化的,看到文章中:線程B CAS 失敗會發起偏向鎖撤銷。 此處是線程A 升級爲輕量級鎖,還是重新爭搶? 如果是重新爭搶,失敗的線程會怎樣?

線程A修改MarkWord中的信息,修改鎖的標識爲00,升級爲輕量級鎖;A已經持有偏向鎖,從偏向鎖升級爲輕量級鎖,是不需要再去重新爭搶的,線程B會自旋嘗試獲取輕量級鎖;

2、線程A、線程B同時到來,是不是直接就走輕量級鎖,而跳過偏向鎖,此是爭搶失敗的線程,發生自旋操作,如果自旋失敗,我看文章是升級到重量級鎖,那麼是線程A、B同時升級到重量級鎖的爭搶嗎?

走不走偏向鎖是跟開不開啓偏向鎖有關的,可以用idea進行測試,加入參數-XX:+UseBiasedLocking -XX:BiasedLockingStartupDelay=0AB線程中,A線程先持有鎖,那麼B自旋失敗後就會把鎖膨脹成重量級鎖,這時候A就是持有了重量級鎖,B就是處於阻塞隊列了(被放在_entryList裏),等A釋放後,B纔有機會獲取到鎖;

3、 jvm 是不是會自行根據當前併發,直接選擇是採用偏向鎖、輕量級、重量級,還是必須是從偏向鎖過渡到重量級鎖?

偏向鎖默認是不開啓的,如果要開啓可以用上面第(2)說的方法,不開啓就默認先獲取到輕量級鎖,然後再升級到重量級鎖,這其實是對鎖的一種優化。因爲加鎖、釋放鎖的成本,要比自旋等待獲取鎖的成本高很多。

4、ThreadA在獲得輕量級鎖後,其RecordLock裏存儲着鎖對象頭的Mark word信息,將鎖對象的Mark Word更新爲指向Lock Record的指針,在ThreadB自旋失敗後,進行鎖膨脹,修改爲重量級鎖,這裏有三個問題:
1)ThreadB修改爲重量級鎖,是修改的 Lock Record中存儲的Mark word的信息麼?

2)此時鎖對象的Mark Word指向的Lock Record的指針是 ThreadB的麼?

3)在ThreadB將鎖膨脹爲重量級鎖之後,正在執行中的ThreadA怎麼處理?

1)線程B膨脹爲重量級鎖,是基於Monitor了,不是再修改markword;

2)所以第二個問題不存在;

3)鎖膨脹爲重量級鎖之後,ThreadA繼續運行,直到運行結束。

5、線程B多次自旋失敗後,將鎖升級爲重量級鎖之後,線程A就直接擁有了這把重量級鎖,然後Monitor對象中_owner存儲的是線程A的地址指針,而線程B則加入到__EntryList隊列中進行阻塞,等待被喚醒,那此時,鎖對象裏的對象頭裏的Mark Word信息是不會改變的,仍然存儲的是A的指針,是等到線程A釋放鎖的時候再去將Mark Word裏的鎖標識進行修改麼(修改爲重量級鎖10)

Mark word存儲的不再是輕量級鎖中指向Lock Record的指針,升級爲重量級鎖之後存儲的就是Monitor了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章