1. 程式人生 > 程式設計 >基於synchronized修飾靜態和非靜態方法

基於synchronized修飾靜態和非靜態方法

前言

最近被問到了這個問題,第一次回答的也是很不好,在此參考網上答案進行整理記錄。供大家學習參考。

Synchronized修飾非靜態方法

Synchronized修飾非靜態方法,實際上是對呼叫該方法的物件加鎖,俗稱“物件鎖”。

Java中每個物件都有一個鎖,並且是唯一的。假設分配的一個物件空間,裡面有多個方法,相當於空間裡面有多個小房間,如果我們把所有的小房間都加鎖,因為這個物件只有一把鑰匙,因此同一時間只能有一個人開啟一個小房間,然後用完了還回去,再由JVM 去分配下一個獲得鑰匙的人。

情況1:同一個物件在兩個執行緒中分別訪問該物件的兩個同步方法

結果:會產生互斥。

解釋:因為鎖針對的是物件,當物件呼叫一個synchronized方法時,其他同步方法需要等待其執行結束並釋放鎖後才能執行。正如上面所解釋的,相當於一個物件只有一把鑰匙了,裡面的兩個同步方法是兩個房間,因此,同一時間只能用一個鑰匙訪問一個方法。

情況2:不同物件在兩個執行緒中呼叫同一個同步方法

結果:不會產生互斥。

解釋:因為是兩個物件,就相當於兩個大房子,彼此之間互不干擾,具有兩把鑰匙。鎖針對的是物件,並不是方法,所以可以併發執行,不會互斥。形象的來說就是因為我們每個執行緒在呼叫方法的時候都是new 一個物件,那麼就會出現兩個空間,兩把鑰匙。

Synchronized修飾靜態方法

Synchronized修飾靜態方法,實際上是對該類物件加鎖,俗稱“類鎖”。

情況1:用類直接在兩個執行緒中呼叫兩個不同的同步方法

結果:會產生互斥。

解釋:因為對靜態物件加鎖實際上對類(.class)加鎖,類物件只有一個,可以理解為任何時候都只有一個空間,裡面有N個房間,一把鎖,因此房間(同步方法)之間一定是互斥的。

注:上述情況和用單例模式宣告一個物件來呼叫非靜態方法的情況是一樣的,因為永遠就只有這一個物件。所以訪問同步方法之間一定是互斥的。

情況2:用一個類的靜態物件在兩個執行緒中呼叫靜態方法或非靜態方法

結果:會產生互斥。

解釋:因為是一個物件呼叫,同上。都呼叫靜態方法的時候,相當於是同一個類鎖,用的都是同一個類物件。

都呼叫非靜態方法的時候,相當於是同一個物件鎖。

情況3:一個物件在兩個執行緒中分別呼叫一個靜態同步方法和一個非靜態同步方法

結果:不會產生互斥。

解釋:因為雖然是一個物件呼叫,但是兩個方法的鎖型別不同,呼叫的靜態方法實際上是類物件在呼叫,即這兩個方法產生的並不是同一個物件鎖,因此不會互斥,會併發執行。

例子

pulbic class Something(){
  public synchronized void isSyncA(){}
  public synchronized void isSyncB(){}
  public static synchronized void cSyncA(){}
  public static synchronized void cSyncB(){}
}

那麼,加入有Something類的兩個例項a與b,那麼下列哪組方法可以被1個以上執行緒同時訪問呢?

a. x.isSyncA()與 x.isSyncB()
b. x.isSyncA()與 y.isSyncA()
c. x.cSyncA()與 y.cSyncB()
d. x.isSyncA()與 Something.cSyncA()

這裡,很清楚的可以判斷:

a,都是對同一個例項的synchronized域訪問,因此不能被同時訪問

b,是針對不同例項的,因此可以同時被訪問

c,因為是static synchronized,所以不同例項之間不會被限制

d,書上的答案是可以被同時訪問的,答案理由是synchronzied的是例項方法與synchronzied的類方法由於鎖定(lock)不同的原因。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。