2013-03-12 75 views
39
synchronized方法

比方說,我有一個synchronized方法上的一些類:重寫在Java中

abstract class Foo { 
    public synchronized void foo() { // synchronized! 
     // ... 
    }; 
} 

,我使用synchronized修飾符推翻它沒有

class Bar extends Foo { 
    @Override 
    public void foo() {    // NOT synchronized! 
     super.foo(); 
     // ... 
    } 
} 

我有幾個關於此場景的具體問題:

  1. 重寫的方法b e也隱含地同步了?
  2. 如果不是,那麼super-呼叫將會同步嗎?
  3. 如果沒有super -call,什麼都會被同步?
  4. 有沒有辦法強制重寫方法使用​​(我注意到抽象方法定義或接口內的方法定義不允許synchronized關鍵字)?
+0

參見http://stackoverflow.com/questions/12684850/how-can-i-ensure-that-an-重寫方法同步 – rgettman 2013-03-12 23:57:32

+1

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4294756同步不是方法簽名的一部分,而是方法實現的一部分。 – flup 2013-03-13 00:01:04

回答

41
public synchronized void foo() { // synchronized! 
    // ... 
}; 

在本質上是一樣的:

public void foo() { 
    synchronized (this) { // synchronized! 
     // ... 
    } 
}; 

後者更明確,因此使用這種形式我一般會建議。或者更好地使用一個私有字段的鎖而不是「外部」對象。

所以:1.第2.是的。 3.編號4.標記方法final並調用protected方法可能被覆蓋。

public final void foo() { 
    synchronized (this) { 
     fooImpl(); 
    } 
}; 
protected void fooImpl() { 
    // ... 
} 

和往常一樣,你可能會更好地使用委託而不是繼承。

+0

+1這是一個很好的看待它的方式!謝謝! – 2013-03-13 00:07:55

+0

使用fooImpl是正確的方法,但仍然提醒我[ClassLoader.loadClassInternal](http://bugs.sun.com/view_bug.do?bug_id=4670071)當然,可以通過'monitorExit' /'moniorEnter'在fooImpl中作弊 – bestsss 2013-04-21 19:58:06

+0

@bestss即使你編寫自己的字節碼,監視器輸入/輸出也應該匹配。 (IIRC在規範中有一些特殊的餘地,但沒有任何合理的實現。)雖然'fooImpl'可以「等待」。 – 2013-04-21 20:03:43

20

重寫同步方法時無法使用同步可能導致運行時錯誤。作爲一種安全措施,您可以打開一個Eclipse檢查器來檢測這種情況。 默認值爲「忽略」。 「警告」也是一個有效的選擇。 preferences

這將產生這樣的信息:

enter image description here

enter image description here

+3

+1這很好知道! – 2013-03-13 00:18:25