57

我想知道如果我在同一个对象上同步两次,在 Java 中是否会出现任何奇怪的行为?

场景如下

pulbic class SillyClassName {

    object moo;
    ...
    public void method1(){
        synchronized(moo)
        {
            ....
            method2();
            ....
        }
    }

    public void method2(){
        synchronized(moo)
        {
            doStuff();
        }
    }
}

两种方法都使用对象并在其上同步。第二种方法被第一种方法调用时会因为被锁定而停止吗?

我不这么认为,因为它是同一个线程,但我不确定可能会出现任何其他奇怪的结果。

4

6 回答 6

83

可重入

同步块使用可重入锁,这意味着如果线程已经持有锁,它可以重新获取它而不会出现问题。因此,您的代码将按预期工作。

请参阅Java 教程页面Intrinsic Locks and Synchronization的底部。

自 2015 年 1 月起引用……</p>

可重入同步

回想一下,一个线程不能获得另一个线程拥有的锁。但是线程可以获取它已经拥有的锁。允许一个线程多次获取同一个锁可以实现重入同步。这描述了一种情况,同步代码直接或间接调用一个也包含同步代码的方法,并且两组代码都使用相同的锁。如果没有可重入同步,同步代码将不得不采取许多额外的预防措施来避免线程导致自身阻塞。

于 2008-10-30T11:45:20.540 回答
4

我认为我们必须为您尝试做的事情使用可重入锁。这是来自http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html的片段。

我们所说的可重入锁是什么意思?简单来说就是有一个与锁相关的获取计数,如果持有锁的线程再次获取它,获取计数就会增加,然后需要释放两次锁才能真正释放锁。这与同步的语义相似;如果一个线程进入一个由该线程已经拥有的监视器保护的同步块,该线程将被允许继续,当线程退出第二个(或后续)同步块时,锁不会被释放,而只会被释放当它退出它进入受该监视器保护的第一个同步块时。

虽然我没有尝试过,但我想如果你想做上面的事情,你必须使用可重入锁。

于 2012-04-04T20:31:51.360 回答
2

Java 似乎完全支持同一线程对一个对象的嵌套锁。这意味着如果一个线程对一个对象有一个外部锁和一个内部锁,而另一个线程试图锁定同一个对象,那么第二个线程将被挂起,直到两个锁都被第一个线程释放。

我的测试是在 Java 6 SE 下完成的。

于 2011-11-10T20:26:14.183 回答
1

在 java 中,synchronized方法上的关键字基本上与当前对象同步,因此实际上它正在隐式执行您上面建议的操作。

在一种方法中同步一个对象,然后在另一种方法中同步同一个对象,您不会遇到问题,因为正如您所说,当前线程已经持有该对象的锁。

于 2008-10-30T11:40:09.863 回答
1

没问题。在您的示例中,(一旦您修复代码以消除您将获得的编译警告;)),同步可确保方法 1 和方法 2 中的块不会同时执行。

这就是同步的重点。:)


编辑:对不起,错过了你的部分问题,但菲尔回答了。总而言之,单个线程不能自己死锁。

于 2008-10-30T11:41:14.417 回答
0

不,如果第一种方法调用第二种方法,则不会停止。不会出现奇怪的结果(除了检查锁的轻微开销。这无关紧要。从 Java 6 开始,您在 JVM - Java SE 6 性能白皮书中进行了锁粗化。)

例如,看一下 java.util.Vector 的源代码。在同步方法中有很多对其他同步方法的调用。

于 2008-10-30T15:46:24.437 回答