- 說到輕量級鎖,我們必須先說一下輕量級鎖是什么?
synchronized在JDK1.6之后的優化鎖后,一共有四種鎖階段:
無鎖 --> 偏向鎖 --> 輕量級鎖 --> 重量級鎖
而輕量級鎖,正處於是第三種階段。
那么如何才會觸發偏向鎖升級為輕量級鎖?偏向鎖又是如何升級為輕量級鎖的呢?
1》如何觸發偏向鎖升級為輕量級鎖呢?
①線程A此時已占有鎖對象資源,鎖對象【Mark Word】中線程ID指向線程A;
②線程B此時訪問同步代碼塊,試圖搶占資源,通過CAS修改Mard Word,但由於線程A已占有鎖對象資源,
此時CAS修改失敗;
③那么此時將會觸發偏向鎖升級為輕量級鎖
2》偏向鎖在升級為輕量級鎖時,會先撤銷偏向鎖,那么是如何撤銷的呢?
①首先等線程A在安全節點阻塞(類似於GC前線程在安全節點阻塞);
②判斷線程A是否還存活,如果線程A還存活;
③判斷線程A是否繼續競爭鎖,如果不競爭,線程B獲得偏向鎖;
④如果競爭,則線程A和線程B同時升級為搶占輕量級鎖
- synchronized和對象表頭(即Mark Word)的關系可以說是息息相關,那么我們先看一下各個鎖級別表頭情況:
- 由與輕量級鎖的Mark Word只剩下了【指向線程棧中鎖記錄的指針】和【鎖標志位】,那么具體是什么格式呢?
大致流程是這樣:
1》偏向鎖撤銷之后(偏向狀態為0),現在無論是A線程還是B線程執行同步代碼塊進行加鎖,都在自己的線程幀棧中創建一個鎖記錄【Lock Record】; 2》線程A此時搶占鎖,將Object中的【Mark Word】拷貝到線程棧中的【Lock Record】中的【displaced hdr】; 3》將鎖記錄中的【owner】指針指向加鎖的對象; 4》將鎖對象的對象頭【Mard Word】替換為鎖記錄的指針; 5》此時鎖標志位是00,為輕量級鎖。
- 那么我看下如下代碼,synchronized又是如何實現可重入的呢?
synchronized(obj){
synchronized(obj){ //①
synchronized(obj){
}
}
}
synchronized在輕量級鎖上的重入原理可以這樣理解:
線程棧中有一個初始的【Lock Record】,其中【displaced hdr】是從【Mard Word】中拷貝出來的,
當代碼執行到①處時,此時會向線程棧中添加一個【displaced hdr】為NULL的【Lock Record】,
如果繼續使用synchronized進行重入時,會繼續向線程棧中添加【displaced hdr】為NULL的【Lock Record】對象。
釋放鎖的原理我腳的大家應該猜到了,就是像棧一樣,從下至上每次排出一個【Lock Record】。
- 輕量級鎖解鎖過程是個什么樣的呢?
當線程在輕量級鎖解鎖過程,先通過CAS將線程棧中鎖記錄【Lock Record】的【Diplaced Header】,
替換至鎖對象中。
若替換成功,說明線程已經執行完同步代碼塊,該期間沒有任何多余線程進行競爭,輕量級鎖解鎖。
若替換失敗,說明線程還未執行完同步代碼塊,若此時鎖對象資源仍存在競爭,並有其他線程加入競爭,則鎖將膨脹至重量級鎖。
- 輕量級鎖的優缺點
輕量級鎖優點主要是采用自旋的方式來處理線程競爭的,自旋操作可以避免線程阻塞、喚醒等操作,從而減少線程上下文切換而對服務器性能的消耗。
不過如果存在某線程占用鎖資源時間過長,從而導致其他線程長時間處於自旋狀態,會嚴重消耗CPU資源,使得CPU使用率飆升,
所以此時需要引入重量級鎖,來達到服務器性能上的平衡。
了解其他: