對象鎖(方法鎖),是針對一個對象的,它只在該對象的某個內存位置聲明一個標識該對象是否擁有鎖,所有它只會鎖住當前的對象,一般一個對象鎖是對一個非靜態成員變量進行synchronized修飾,或者對一個非靜態成員方法進行synchronized進行修飾,對於對象鎖,不同對象訪問同一個被synchronized修飾的方法的時候不會阻塞
類鎖是鎖住整個類,當有多個線程來聲明這個類的對象時候將會被阻塞,直到擁有這個類鎖的對象唄銷毀或者主動釋放了類鎖,這個時候在被阻塞的線程被挑選出一個占有該類鎖,聲明該類的對象。其他線程繼續被阻塞住。
無論是類鎖還是對象鎖,父類和子類之間是否阻塞沒有直接關系。當對一個父類加了類鎖,子類是不會受到影響的,相反也是如此。因為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塊是可重入的,所以當你訪問一個對象鎖的方法的時候,在該方法中繼續訪問其他對象鎖方法是不會被阻塞的。