2014-10-29 98 views
2

我有這樣的代碼:Java的同步方法調用不同步方法

public class Example { 
    public synchronized void doSomething() { 
     // ... 
     doSomethingElse(); 
     // ... 
    } 

    private void doSomethingElse() { 
     // ... 
    } 
} 

由於doSomething是隻有在doSomethingElse被調用,doSomething是同步的地方,它仍然需要使doSomethingElse同步?

Java語言規範在關於類的beginning of chapter 8中說:「同步方法在執行主體之前自動鎖定對象並在返回時自動解鎖對象。我假設調用另一個方法沒有返回,所以上面的代碼應該是正確的。

JLS example 8.4.3.6-1在同步監視器上似乎證實我的理解。

另一方面,我猜doSomethingElse同步不會傷害;除了可能按照What is the synchronization cost of calling a synchronized method from a synchronized method?(我不關心這麼多;正確性更重要)的小性能命中。

我錯過了什麼嗎?

+0

除了這樣一個事實,即從外部可見的對象上同步並不是一個很好的做法,代碼就很好。 – biziclop 2014-10-29 16:29:10

+0

@biziclop您能否詳細說明爲什麼同步可見(即公共)功能是不好的做法?任何參考? – user949300 2014-10-29 16:32:38

+0

@ user949300不可見的函數,對可見對象進行同步是問題所在。 (就你而言,你在'this'上同步)。問題是,如果你創建一個對象並將它傳遞給一些未知的代碼('Example ex = new Example(); foo.doSomethingWith(ex)'),那麼代碼也可以在'ex'上同步,從而干擾你的同步。 – biziclop 2014-10-29 16:35:09

回答

3

是否還需要使doSomethingElse同步?

不是。由於該方法是私有的,唯一可以調用它的上下文同步,所以doSomethingElse不需要同步。

注意,它不會傷害做出doSomethingElse同步的,原因有二:

  • 萬一別人改變你的代碼中調用doSomethingElse從是同步的其他一些地方,你會是安全的。重新輸入線程已擁有的鎖定非常便宜,因此您不必擔心性能後果。
  • 當其他人閱讀你的代碼,並看到你從doSomethingElse訪問共享資源沒有同步,他們並不感到驚訝,你如何擺脫這種情況。

另請注意,兩種方法都是非靜態的,這一點很重要。如果doSomethingElsestatic並且需要訪問可變的靜態資源,則需要將其與doSomething分開同步。

+0

正確,但是...請注意,使'doSomethingElse()**同步**可能是一個好主意,以防將來它可能會在別處使用。 (或者至少在未來的編碼器中留下警告)。而且,假設JVM在獲得線程已經鎖定的同步鎖的時候非常有效 - 即調用很多嵌套的同步方法(理論上)非常快。 – user949300 2014-10-29 16:42:48

+0

@ user949300感謝您的評論,我編輯了答案以反映這一點。 – dasblinkenlight 2014-10-29 16:49:27