1. 程式人生 > 其它 >sychronized 鎖升級

sychronized 鎖升級

sychronize有幾種鎖

sychronize
1.6之前,只存在重量級鎖,也就是一個執行緒拿到鎖之後,其他沒有拿到鎖的執行緒只能阻塞。
1.6之後,新加了偏向鎖和輕量級鎖(自旋鎖)。

無鎖

無鎖是指沒有對資源進行鎖定,所有的執行緒都能訪問並修改同一個資源,但同時只有一個執行緒能修改成功。

也就是說,理想情況下,所有獲取鎖的執行緒都能夠在第一次嘗試的時候就成功,也就是沒有真正發生競爭,此時,sychronized不會真正的加鎖。
實際上不是這樣。當物件剛被new出來的時候,沒有執行緒進行訪問,此時是無鎖狀態,一旦有執行緒來訪問,其實第一個執行緒會加偏向鎖。或者偏向鎖撤銷 物件頭中的mark word 是空的時候 也是無鎖狀態。

也就是不存在多個執行緒訪問,互相不衝突,大家維持友好的無鎖狀態這種事。

偏向鎖

偏向鎖是指當一段同步程式碼一直被同一個執行緒所訪問時,即不存在多個執行緒的競爭時,那麼該執行緒在後續訪問時便會自動獲得鎖,從而降低獲取鎖帶來的消耗,即提高效能。

也就是說,此時也沒有發生真正的競爭,可以理解為不存在第二個執行緒來獲取鎖,當物件被第一個執行緒訪問,當鎖物件第一次被執行緒獲取的時候,虛擬機器會把物件頭中的標誌位設為01、把偏向模式設定為1,表示進入偏向模式。同時使用CAS操作把獲取到這個鎖的執行緒的ID記錄在物件的Mark Word中,如果CAS操作成功,持有偏向鎖的執行緒以後每次進入這個鎖相關的同步塊時。虛擬機器都可以不再進行任何同步操作(例如加鎖、解鎖以及對Mark Word的更新操作等)。

輕量級鎖/自旋鎖

輕量級鎖是指當鎖是偏向鎖的時候,卻被另外的執行緒所訪問,此時偏向鎖就會升級為輕量級鎖,其他執行緒會通過自旋(關於自旋的介紹見文末)的形式嘗試獲取鎖,執行緒不會阻塞,從而提高效能。

輕量級鎖的獲取主要由兩種情況:① 當關閉偏向鎖功能時;② 由於多個執行緒競爭偏向鎖導致偏向鎖升級為輕量級鎖。

也就是說,一旦發生了兩個執行緒同時獲取一把鎖的情況,偏向鎖就不合適了,會升級成輕量級鎖,之所以稱之為“輕量”,是因為其他沒有獲取到鎖的執行緒並不會進入阻塞狀態,而是會進入“自旋”,其實就是進入迴圈,迴圈內會嘗試繼續獲取鎖。

可以看一下偏向鎖到輕量級鎖的升級過程

  1. 在程式碼即將進入同步塊的時候,如果此同步物件沒有被鎖定(鎖標誌位為01
    狀態),虛擬機器首先將在當前執行緒的棧幀中建立一個名為鎖記錄的空間,用於儲存鎖物件目前的Mark Word拷貝(官方為這份拷貝加了個字首Displaced)。
  2. 然後虛擬機器將使用CAS操作嘗試把物件的Mark Word更新為指向Lock Record的指標。如果這個更新動作成功了,即代表該執行緒擁有了這個物件的鎖,並且物件Mark Word的鎖標誌位(Mark Word的最後兩個位元)將轉變為00,表示此物件處於輕量級鎖定狀態。
  3. 如果這個操作失敗了,那就意味著至少存在一條執行緒與當前執行緒競爭獲取該物件的鎖。虛擬機器首先會檢查物件的Mark Word是否指向當前執行緒的棧幀。如果是,說明當前執行緒已經擁有了這個物件的鎖,那直接進入同步塊繼續執行就可以了,否則就說明這個鎖物件已經被其他執行緒搶佔了。當前執行緒會進行自旋。
  4. 如果出現兩條以上的執行緒爭用同一個鎖,或者當前執行緒自旋失敗(嘗試到一定次數,預設10次)的情況,那輕量級鎖就不再有效,必須要膨脹為重量級鎖,鎖標誌的狀態值變為10,此時Mark Word中儲存的就是指向重量級鎖監視器ObjectMonitor(互斥量)的指標,後面等待鎖的執行緒也必須進入阻塞狀態。

重量級鎖

重量級鎖是指當有一個執行緒獲取鎖之後,其餘所有等待獲取該鎖的執行緒都會處於阻塞狀態。

重量級鎖通過物件內部的監視器(monitor)實現,而其中 monitor 的本質是依賴於底層作業系統的 Mutex Lock 實現,作業系統實現執行緒之間的切換需要從使用者態切換到核心態,切換成本非常高。

簡而言之,重量級鎖和我們平常使用的lock區別不大,一旦有一個執行緒獲取到了鎖,其他沒有獲取到鎖的執行緒都只能進入阻塞狀態排隊。

鎖升級狀態

所以,鎖升級有兩條線路:

  1. 偏向鎖開啟的情況下,當物件被new出來,此時是無鎖,當第一個執行緒來訪問並獲取鎖的時候,加一個偏向鎖,如果在第一個執行緒持有偏向鎖期間,有其他的執行緒也來獲取鎖,那麼此時升級為輕量級鎖,如果競爭比較激烈,比如自旋的執行緒嘗試多次仍舊獲取不到鎖,就有可能升級為重量級鎖。也就是無鎖→偏向鎖→輕量級鎖→重量級鎖
  2. 偏向鎖關閉的情況下,當物件被new出來,此時是無鎖,當第一個執行緒來訪問,直接就加輕量級鎖,如果競爭比較激烈,比如自旋的執行緒嘗試多次仍舊獲取不到鎖,就有可能升級為重量級鎖。也就是無鎖→輕量級鎖→重量級鎖

總結

以上是我的思考,有不對的地方歡迎大家指出(我覺得肯定有不對的地方,可是現階段我就是這麼理解的,希望大家積極指出),感謝大家幫助我提高。

參考

synchronized與鎖升級(示例程式碼)
synchronized四種鎖狀態的升級