1. 程式人生 > >java synchronized(靜態同步方法、非靜態同步方法及同步塊)

java synchronized(靜態同步方法、非靜態同步方法及同步塊)

同步方法

  同步方法所擁有的鎖就是該方法所屬的類的物件鎖,換句話說,也就是this物件,而且鎖的作用域也是整個方法,這可能導致其鎖的作用域可能太大,也有可能引起死鎖,同時因為可能包含了不需要進行同步的程式碼塊在內,也會降低程式的執行效率。

同步方法的鎖

  同步方法分為靜態同步方法與非靜態同步方法。

  • 非靜態同步方法

  所有的非靜態同步方法用的都是同一把鎖——例項物件本身,也就是說如果一個例項物件的非靜態同步方法獲取鎖後,該例項物件的其他非靜態同步方法必須等待獲取鎖的方法釋放鎖後才能獲取鎖,可是別的例項物件的非靜態同步方法因為跟該例項物件的非靜態同步方法用的是不同的鎖,所以毋須等待該例項物件已獲取鎖的非靜態同步方法釋放鎖就可以獲取他們自己的鎖。

  • 非靜態同步方法

  所有的靜態同步方法用的也是同一把鎖——類物件本身,這兩把鎖是兩個不同的物件,所以靜態同步方法與非靜態同步方法之間是不會有競態條件的。但是一旦一個靜態同步方法獲取鎖後,其他的靜態同步方法都必須等待該方法釋放鎖後才能獲取鎖,而不管是同一個例項物件的靜態同步方法之間,還是不同的例項物件的靜態同步方法之間,只要它們同一個類的例項物件 .

同步塊

  同步塊,不僅可以更加精確的控制物件鎖,也就是控制鎖的作用域,何謂鎖的作用域?鎖的作用域就是從鎖被獲取到其被釋放的時間。而且可以選擇要獲取哪個物件的物件鎖。但是如果在使用同步塊機制時,如果使用過多的鎖也會容易引起死鎖問題,同時獲取和釋放所也有代價。

同步塊的鎖

  對於同步塊,由於其鎖是可以選擇的,所以只有使用同一把鎖的同步塊之間才有著競態條件,這就得具體情況具體分析了,但這裡有個需要注意的地方,同步塊的鎖是可以選擇的,但是不是可以任意選擇的!這裡必須要注意一個物理物件和一個引用物件的例項變數之間的區別!使用一個引用物件的例項變數作為鎖並不是一個好的選擇,因為同步塊在執行過程中可能會改變它的值,其中就包括將其設定為null,而對一個null物件加鎖會產生異常,並且對不同的物件加鎖也違背了同步的初衷!這看起來是很清楚的,但是一個經常發生的錯誤就是選用了錯誤的鎖物件,因此必須注意:同步是基於實際物件而不是物件引用的!多個變數可以引用同一個物件,變數也可以改變其值從而指向其他的物件,因此,當選擇一個物件鎖時,我們要根據實際物件而不是其引用來考慮!作為一個原則,不要選擇一個可能會在鎖的作用域中改變值的例項變數作為鎖物件!

Notice

  1. 呼叫同一個物件中非靜態同步方法的執行緒將彼此阻塞。如果是不同物件,則每個執行緒有自己的物件的鎖,執行緒間彼此互不干預。
  2. 呼叫同一個類中的靜態同步方法的執行緒將彼此阻塞,它們都是鎖定在相同的Class物件上。
  3. 靜態同步方法和非靜態同步方法將永遠不會彼此阻塞,因為靜態方法鎖定在Class物件上,非靜態方法鎖定在該類的物件上。
  4. 對於同步程式碼塊,要看清楚什麼物件已經用於鎖定(synchronized後面括號的內容)。在同一個物件上進行同步的執行緒將彼此阻塞,在不同物件上鎖定的執行緒將永遠不會彼此阻塞。