我想知道在Java中,如果我在同一个对象上同步两次,我会得到任何奇怪的行为吗?
方案如下
pulbic class SillyClassName {
object moo;
...
public void method1(){
synchronized(moo)
{
....
method2();
....
}
}
public void method2(){
synchronized(moo)
{
doStuff();
}
}
}
两种方法都使用该对象并在其上进行同步。第一种方法调用的第二种方法会因为它被锁定而停止吗?
我不这么认为,因为它是相同的线程,但我不确定可能发生的任何其他奇怪的结果。
答案 0 :(得分:67)
同步块使用可重入锁,这意味着如果线程已经拥有锁,它可以毫无问题地重新获取它。因此,您的代码将按预期工作。
请参阅Java Tutorial页面Intrinsic Locks and Synchronization的底部。
报价截至2015-01 ......
可重入同步
回想一下,线程无法获取另一个线程拥有的锁。但是一个线程可以获得它已经拥有的锁。允许线程多次获取同一锁定可启用可重入同步。这描述了一种情况,其中同步代码直接或间接地调用也包含同步代码的方法,并且两组代码使用相同的锁。如果没有可重入同步,同步代码必须采取许多额外的预防措施,以避免线程导致自身阻塞。
答案 1 :(得分:4)
我认为我们必须使用可重入锁来实现您的目标。这是http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html的摘录。
折返锁是什么意思?简单地说,存在与锁相关联的获取计数,并且如果持有锁的线程再次获取它,则获取计数递增,然后需要释放锁两次以真正释放锁。这与synchronized的语义相似;如果一个线程进入一个由该线程已经拥有的监视器保护的同步块,则该线程将被允许继续,并且当该线程退出第二个(或后续)同步块时将不会释放该锁,但只会被释放当它退出第一个同步块时,它会被该监视器保护。
虽然我还没试过,但我想如果你想做你上面所做的,你必须使用一个可重入的锁。
答案 2 :(得分:2)
Java似乎完全支持同一线程对一个对象的嵌套锁。这意味着如果一个线程在一个对象上有一个外部锁和一个内部锁,另一个线程试图锁定同一个对象,那么第二个线程将被挂起,直到两个锁被第一个释放线程。
我的测试是在Java 6 SE下完成的。
答案 3 :(得分:1)
没问题。在您的示例中,(一旦您修复代码以消除您将获得的编译警告;)),同步将确保方法1和方法2中的块不会同时执行。
这就是同步点。 :)
编辑:对不起,你错过了部分问题,但菲尔回答了。总而言之,单个线程无法自行解锁。
答案 4 :(得分:0)
在java中,方法上的synchronized
关键字基本上在当前对象上同步,所以实际上它正在隐含地执行你上面提到的建议。
在一个方法中同步一个对象然后在另一个方法中同步同一个对象时,您不会遇到问题,因为正如您所说,当前线程已经锁定了该对象。
答案 5 :(得分:0)
不,如果先调用,第二种方法不会停止。不会出现奇怪的结果(除了检查锁定的轻微开销。这不重要。从Java 6开始,你在JVM中锁定了粗糙 - http://java.sun.com/performance/reference/whitepapers/6_performance.html)
例如,看一下java.util.Vector的源代码。在synchronized方法中有很多对其他同步方法的调用。