JAVA多線程的初級認識4-鎖的基本認識

Java中多線程的技術必然要了解的必然是鎖~鎖保證多線程的數據安全。所以不多說進入主題。

最輕量級的鎖Volatile

當然這是因爲它只能修飾變量,而且相對於synchronized關鍵字輕量了很多~

對於變量增加了volatile的修飾,表示該數據的寫和讀都直接同步到主內存,所以保證該變量的任何修改對於其他線程是可見的。

我們可以查看關於修飾volatile變量的編譯文件和指令,可以看出~裏面會有一個lock的彙編指令。具體實現是通過內存屏障,具體如圖:
在這裏插入圖片描述
同時volatile還有一個功能就是防止指令重排序。java代碼到最終執行的機器碼要經過幾次指令排序~如下圖:
在這裏插入圖片描述
但是volatile有些時候可能會導致誤用,比如
volatile int i=0;

{
    i++;
}

這段代碼再多線程的時候可能會出現問題~具體原因是i++非原子操作。可能存在覆蓋的情況

synchronized

這個關鍵字應該很不陌生。Java 1.6之後~由於synchronized的鎖太重性能很是問題,所以升級爲偏向鎖,輕量鎖,重量鎖,根據不同情況使用不同鎖。

作用範圍

  1. 修飾實例方法
    表示對於當前實例加鎖,進入任何該對象實例修飾的代碼塊均需要提前獲得鎖。
  2. 修飾靜態方法
    表示對於該類進行加鎖,進入該類修飾的代碼塊需要獲取當前類的鎖。
  3. 修飾代碼塊
    指定加鎖對象,進入加鎖對象的代碼塊~需要提前獲得該對象鎖

鎖的存儲

由於所是鎖資源對象~所以要了解一下對象在堆上的存儲。一共分爲三個區域對象頭(header),示例數據(instanceData),和對齊填充(padding)。如圖:
在這裏插入圖片描述
通過cpp源碼可以瞭解到~一個對象的創建都會創建一個instanceOopDesc(數組是arrayOopDesc)在文件instanceOop.hpp裏面。
在這裏插入圖片描述
可以看到它集成了oopDesc,而oopDesc裏面包含兩個成員變量(_mark,_metadata).其中_mark是markOop類型,也就是所謂的Mark World。記錄了對象和鎖相關的數據。

MarkWorld

markOop類型記錄在markOop.hpp文件中,如下:
在這裏插入圖片描述
該部分記錄了和鎖相關的所有信息~MarkWorld具體會有5種情況:
在這裏插入圖片描述

鎖的類型

1.6後鎖的類型分爲無鎖,偏向鎖,輕量鎖,重量鎖。

偏向鎖

最簡單的鎖,支持重入,場景:經常是單線程進行鎖定~即在對象_mark中通過CAS標記爲偏向鎖,同時將線程ID記錄在對象中即可。流程如下:
在這裏插入圖片描述
可以通過JVM參數 UseBiasedLocking來控制是否開啓。
當通過CAS失敗獲取偏向鎖的時候,就會升級爲輕量鎖

輕量級鎖

當偏向鎖存在競爭的時候,即CAS設置偏向鎖的時候失敗,那麼失敗的線程將進行自旋操作(自旋鎖)。自旋鎖即採用for循環,不斷的去進行獲取鎖的操作,所以針對同步代碼塊執行快的操作,是ok的。但是如果過長,則會造成cpu資源的浪費。
輕量級鎖的更新流程:
在這裏插入圖片描述
而鎖對象的markWorld也進行相應的更改

  • 線程在自己的棧裏面創建LockRecord
  • 將鎖對象的markWorld複製過來
  • 將LockRecord的owner指針指向鎖對象
  • 將鎖對象的MarkWorld替換爲指向LockRecord的指針
    如下圖:
    在這裏插入圖片描述
    隨後更改後:
    在這裏插入圖片描述
    可以通過JVM參數preBlockSpin來控制自旋數量
    當CAS設置鎖對象的MarkWorld失敗的時候,就會膨脹微重量級鎖。

重量級鎖

重量級鎖就是1.5之前的synchronized鎖~通過java -p看class信息可以看出指令即monitorenter和monitorexit來控制鎖的加鎖和釋放。
在這裏插入圖片描述
所有的Java Object天生攜帶一個monitor,可以認爲是一個同步對象,通過對於對象監視器的爭搶修改鎖標誌從而進行多線程同步。在markOop.hpp源碼可以看到:
在這裏插入圖片描述
monitor的操作依賴於操作系統的MutexLock(互斥鎖)來實現的,線程一旦被阻塞,那麼就會從用戶態切換到內核調度狀態。頻繁的內核態和用戶態的切換回影響鎖的性能。鎖競爭monitor的邏輯如下圖:
在這裏插入圖片描述

最後貼一張基於wait和notify的鎖加入和釋放的圖:
在這裏插入圖片描述
拋磚引玉,整理學習筆記。如有問題隨時溝通交流~謝謝

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