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其他執行緒才能獲得鎖,因而,不可中斷性實現。
另外,有的面試題會問非同步方法和同步方法同時呼叫會不會同步執行,答案是不會。
因為,非同步方法執行時不會去考慮執行緒進入數以及獲得鎖一系列流程,直接開始執行,怎麼可能同步執行呢