1. 程式人生 > >Java 方法鎖、物件鎖、類鎖

Java 方法鎖、物件鎖、類鎖

首先介紹一下物件鎖(也叫方法鎖)與類鎖有那些不同。下文中使用物件鎖稱呼代替方法鎖。

  對於物件鎖,是針對一個物件的,它只在該物件的某個記憶體位置宣告一個標誌位標識該物件是否擁有鎖,所以它只會鎖住當前的物件。一般一個物件鎖是對一個非靜態成員變數進行syncronized修飾,或者對一個非靜態方法進行syncronized修飾。對於物件鎖,不同物件訪問同一個被syncronized修飾的方法的時候不會阻塞住。

類鎖是鎖住整個類的,當有多個執行緒來宣告這個類的物件的時候將會被阻塞,直到擁有這個類鎖的物件被銷燬或者主動釋放了類鎖。這個時候在被阻塞住的執行緒被挑選出一個佔有該類鎖,宣告該類的物件。其他執行緒繼續被阻塞住。

無論是類鎖還是物件鎖,父類和子類之間是否阻塞沒有直接關係。當對一個父類加了類鎖,子類是不會受到影響的,相反也是如此。因為synchronized關鍵字並不是方法簽名的一部分,它是對方法進行修飾的。當子類覆寫父類中的同步方法或是介面中宣告的同步方法的時候,synchronized修飾符是不會被自動繼承的,所以相應的阻塞問題不會出現。

注意:這裡的阻塞問題是指的按照正常情況下應該阻塞,而因為synchronized是父類與子類之間不可傳遞導致不會阻塞。那正常情況下阻塞是什麼那,下面會詳細介紹。但是,當一個子類沒有覆蓋父類的方法的時候,這時候通過子類訪問方法則會產生阻塞。

插入一句:構造方法不可能是真正同步的(儘管可以在構造方法中使用同步塊)。下面截圖給出瞭如何宣告一個物件鎖和如何宣告一個類鎖:

複製程式碼
 1 void myMethod(){
 2     synchronized(this){
 3         //code
 4     }
 5 }
 6 
 7 /*is equvilant to*/
 8 void synchronized myMethod(){
 9     //code
10 }
複製程式碼

當同一個物件線上程1中訪問一個方法,線上程2中再去訪問另外一個加鎖方法,則同樣也會被阻塞.

對於類鎖,則會把整個類鎖住,也就說只能有一個物件擁有當前類的鎖。當一個物件擁有了類鎖之後,另外一個物件還想競爭鎖的話則會被阻塞。兩個物件A,B,如果A正在訪問一個被類鎖修飾的方法function,那麼B則不能訪問。因為類鎖只能在同一時刻被一個物件擁有。相對於物件鎖,則是不同。還是A,B兩個物件,如果A正在訪問物件鎖修飾的function,那麼這個時候B也可以同時訪問。

對於物件鎖,當一個物件擁有鎖之後,訪問一個加了物件鎖的方法,而該方法中又呼叫了該類中其他加了物件鎖的方法,那麼這個時候是不會阻塞住的。這是java通過可重入鎖機制實現的。可重入鎖指的是當一個物件擁有物件鎖之後,可以重複獲取該鎖。因為synchronized塊是可重入的,所以當你訪問一個物件鎖的方法的時候,在該方法中繼續訪問其他物件鎖方法是不會被阻塞的。