2014-10-29 135 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