微信公衆號:IT一刻鐘。大型現實非嚴肅主義現場,一刻鐘與你分享優質技術架構與見聞,作一個有劇情的程序員。關注可第一時間瞭解更多精彩內容,按期有福利相送喲。程序員
以前咱們講了synchronized的原理,以及其中的偏向鎖,送佛送到西,此次咱們來講一說輕量級鎖吧。安全
友情提醒:上面兩篇沒有看過的看官,請先閱讀上面兩篇以後,再讀此篇,這樣效果會更佳哦~微信
開局一張圖。架構
當JVM關閉了偏向鎖模式,對象在建立的時候,Mark Word中存儲的是hash值,年代,是否偏向鎖標誌位爲0,標誌位是01。即一個無鎖不可偏向狀態。學習
輕量級鎖邏輯:spa
1.當線程訪問同步塊,先判斷鎖狀態標誌位,若是是00,則說明是輕量級鎖,JVM會先在當前線程棧幀中分配Lock Record空間;.net
2.將鎖對象頭中的Mark Word拷貝到當前線程的Lock Record中,稱爲Displaced Mark Word,而後使用CAS,將對象頭中的Mark Word修改成指向當前線程棧中Lock Record的指針(如圖)。若是成功,則獲取輕量級鎖,執行同步塊中的代碼,若是失敗,則進行自旋競爭鎖,自旋達到必定的次數若是依舊沒有獲取到鎖,則升級爲重量級鎖(由於自旋會消耗CPU,爲了不無用的自旋,一旦鎖升級爲重量級鎖,就不會恢復到輕量級鎖,自旋的線程會被掛起阻塞住);線程
CAS操做以前堆棧與對象的狀態:3d
CAS操做以後堆棧與對象的狀態:指針
3.執行完同步代碼塊代碼,退出同步代碼塊,使用CAS開始輕量級鎖解鎖,解鎖的條件須要知足如下兩個:
1)對象頭Mark Word中鎖記錄指針是否依舊指向當前線程Lock Record
2)拷貝在當前線程Lock Record的Mark Word信息是否與對象頭中的Mark Word一致
4.若是知足,則成功釋放鎖;
5.若是不知足,則釋放鎖,喚醒被掛起阻塞的線程,開始重量級鎖的競爭。
注:當超過自旋閾值,競爭的線程就會把鎖對象Mark Word指向重量級鎖,致使Mark Word中的值發生了變化,當原持有輕量級鎖的線程執行完畢,嘗試經過CAS釋放鎖時,由於Mark Word已經指向重鎖,再也不是指向當前線程Lock Record的指針,因而解鎖失敗,這時原持有輕量級鎖的線程就會知道鎖已經升級爲重量級鎖。
偏向鎖升級爲輕量級鎖:
1.先在原持有偏向鎖的線程棧幀中分配Lock Record;
2.將對象頭Mark Word拷貝到原持有偏向鎖的線程Lock Record中,而後使用CAS,將對象頭中的Mark Word修改成指向當前線程棧中Lock Record的指針。將原持有偏向鎖的線程升級爲持有偏向鎖的線程;
3.喚醒線程,從安全點繼續執行,執行完畢解鎖。
咱們看個demo,在該demo中重複3次得到鎖,
synchronized(obj){ synchronized(obj){ synchronized(obj){ } } }
假設鎖的狀態是輕量級鎖,如圖反應了Mark Word和線程棧中Lock Record的關係,右邊線程棧中包含3個指向當前鎖對象的Lock Record。其中棧中最高位的Lock Record爲第一次獲取鎖時分配的,其中Displaced Mark word爲鎖對象加鎖前的Mark Word,而以後的鎖重入,則會在線程棧中分配一個Displaced Mark word爲null的Lock Record,用來重入計數。
每次釋放鎖的時候則會刪除對應的Lock Record。 這就是輕量級鎖的實現邏輯,相對於偏向鎖來講,邏輯會稍微簡單一些。
若是以爲學習到了,歡迎轉發加關注,那是我分享的動力呀~