2013-03-11 175 views
12

這是我在this鏈接找到的一段文本。同步Java - 同步靜態方法

「靜態方法

最壞的解決方案是將避免鎖‘’關鍵字的靜態 方法,這意味着它會鎖定在這個類的所有實例。」

爲什麼會同步靜態方法鎖定類的所有實例?它不應該只是鎖定班級嗎?

+7

由於靜態方法適用於所有情況下,鎖定所有實例。 – duffymo 2013-03-11 01:07:27

+0

雖然靜態方法可用於實例,但不應通過實例來訪問它們。他們只應該被靜態訪問。所以作者所說的仍然是不正確的。 – sotn 2013-03-11 01:43:45

+1

@duffymo不,它不鎖*任何*實例。 'synchronized(this)'將在此鎖定期間繼續。 – EJP 2013-03-11 01:51:49

回答

6

這裏是我的測試代碼顯示,你是正確的和文章是有點過於謹慎:

class Y { 
    static synchronized void staticSleep() { 
     System.out.println("Start static sleep"); 
     try { 
      Thread.sleep(2000); 
     } catch (InterruptedException e) { 
     } 
     System.out.println("End static sleep"); 
    } 

    synchronized void instanceSleep() { 
     System.out.println("Start instance sleep"); 
     try { 
      Thread.sleep(200); 
     } catch (InterruptedException e) { 
     } 
     System.out.println("End instance sleep"); 
    } 
} 

public class X { 
    public static void main(String[] args) { 
     for (int i = 0; i < 2; ++i) { 
      new Thread(new Runnable() { 

       public void run() { 
        Y.staticSleep(); 
       } 
      }).start(); 
     } 

     for (int i = 0; i < 10; ++i) { 
      new Thread(new Runnable() { 

       public void run() { 
        new Y().instanceSleep(); 
       } 
      }).start(); 
     } 
    } 
} 

打印:

Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start static sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
Start instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End instance sleep 
End static sleep 
Start static sleep 
End static sleep 

所以static synchronized對的情況下,​​方法沒有關係......

當然,如果在整個系統中使用static synchronised方法,那麼你可以期望它們對多線程系統的吞吐量產生最大的影響,因此可以將它們用於你的危險......

+1

感謝您的測試代碼!即使過於謹慎也不應使作者說得對。實例和類鎖是分開的。這篇文章讓我懷疑神聖的SCJP,特別是因爲作者,他的簡歷是一位專家。 – sotn 2013-03-11 01:36:33

7

上。實際上Foo類的靜態方法的鎖,是一樣的穿着Foo.class鎖(這是唯一的實例):

public static void doSomething() 
{ 
    synchronized(Foo.class) 
    { 
     // ... 
    } 
} 
4

你是對—實際鎖定在Class實例本身,而不是任何類的實例(更不用說所有實例)—但我認爲你是從字面上解釋鏈接頁面。它本身使用短語「一個靜態鎖(一個類鎖)」,所以它的作者很清楚它的鎖定是如何工作的。但是,如果在不同線程中有許多實例都使用同步靜態方法,那麼這些實例將互相鎖定。同步靜態方法不會造成阻塞同步的實例方法,但問題是不管。

32

要理解這一點,最簡單的方法是比較實例方法和靜態方法的鎖定方式。 假設你有Test.java類,它有兩個方法,如下所示。

public class Test{ 
    public synchronized void instanceMethod(){ 
    } 

    public synchronized static void staticMethod(){ 
    } 
} 

同時,類Test,testA和testB有兩個實例。還有兩個線程tA和tB試圖並行訪問類Test。

鎖定在instanceMethod: 當Ta沾到instanceMethod鎖種皮的,TB不能種皮訪問同樣的方法,但結核病仍然是免費調用instanceMethodTESTB。由於對instanceMethod同步是實例級鎖定

鎖定在STATICMETHOD: 然而,當TA沾到STATICMETHOD鎖,鎖無關與種皮或TE​​STB,因爲靜態方法同步是班級鎖定。這意味着TB無法訪問STATICMETHOD可言,直到TA釋放鎖

+0

非常好的解釋鎖定機制的差異。 – asgs 2013-03-11 02:17:43

+1

終於有了關於靜態同步方法的想法。很好的解釋。 – sonia 2014-05-08 11:23:22

+0

是的,這是鎖定實例vs靜態方法的不錯總結。 – JohnMerlino 2014-06-30 20:38:53

2

它不會說'鎖定班級的所有實例「。它說'鎖該類的所有實例。這句話措辭不好,確實不正確,但並不是說你說的話。