synchronized底層原理

zwy2021發表於2021-05-24

synchronized底層原理

通過反編譯class檔案,可以看到synchronized最關鍵的部分是monitor物件。

又因為synchronized關鍵字使用的方法不同,可以將monitor物件使用分為以下兩種情況。

  • synchronized放在方法簽名上

    public synchronized void method(){
        
    }
    

    這時候在反編譯檔案裡,該方法的ACC_SYNCHRONIZED訪問標誌位會被標記

  • synchronized作為物件鎖

    public void method(){
      synchronized(new Object()){
       
      }
    }
    

這時候ACC_SYNCHRONIZED並不會被標記,但是會執行monitorenter和monitorexit命令,從而實現同步。

  • 可以看到雖然只有一個monitorenter但是有兩個monitorexit,這是因為有兩種情況可以讓當前執行緒放棄鎖,即
    • 當前synchronized程式碼塊執行完
    • 發生中斷

monitor物件

其實以上兩種方法都是相同的,ACC_SYNCHRONIZED標誌位是隱式呼叫了monitor物件而已。下面來說一下monitor物件以及它是如何實現運作的。

monitor的資料結構

關於儲存的monitor物件有以下三種可能,對應不同的synchronzied使用方式,

  • synchronzied修飾普通方法——>鎖的是this,也就是呼叫當前方法的例項物件

  • synchronized修飾程式碼塊——>鎖的是synchronized後面括號裡的方法

  • synchronized修飾static方法——>鎖的是類的.class物件

    關於面試的時候會問的各種情況下會不會同步執行,牢記一點

    鎖的物件相同才會同步執行

    鎖的物件相同才會同步執行

    鎖的物件相同才會同步執行

    也就是說,類鎖對普通方法鎖是不存在覆蓋的,下面兩個方法不會同步執行

    public synchronized void method1(){
            
        }
        public  static synchronized void method2(){
            
        }
    

monitor執行機制

如果一個執行緒執行到一個同步程式碼塊,如果執行緒進入數為0,則該執行緒可擁有此monitor物件的鎖,遇到monitorenter,進入數+1,遇到monitorexit,進入數-1。

如果目前執行緒進入數不為0,則當前執行緒不能獲得此monitor物件的鎖,需要等待。

synchronized的可重入性,不可中斷性是如何保障的呢?

monitor物件的執行緒進入數不是0和1,如果發生重入,進入數+1即可。

不可中斷性:一個執行緒獲取鎖後,其他執行緒必須阻塞或等待,不能搶佔,按照上面的執行機制,必須執行緒進入數=0其他執行緒才能獲得鎖,因而,不可中斷性實現。

另外,有的面試題會問非同步方法和同步方法同時呼叫會不會同步執行,答案是不會。

因為,非同步方法執行時不會去考慮執行緒進入數以及獲得鎖一系列流程,直接開始執行,怎麼可能同步執行呢

相關文章