【发布时间】:2015-04-16 14:01:47
【问题描述】:
我对Java synchronized() 块的理解是,如果一个线程已经拥有一个对象上的锁,它可以进入同一个对象上同步的不同块(重入同步)。下面,我认为JVM使用引用计数来增加/减少线程获取锁的次数,并且只有在计数为零时才会释放锁。
所以我的问题是,如果有人遇到这样的一段代码:
synchronized(this)
{
if (condition == WAITING)
{
synchronized(this)
{
condition = COMPLETE;
notify();
try
{
wait();
}
catch(InterruptedException e)
{
}
}
}
else
condition = READY;
}
当调用 wait() 时具体会发生什么?它只是减少计数,还是不考虑计数就释放锁?
在第一种情况下,在我看来,如果发生锁重入,它会产生死锁,因为它仍然拥有锁,因此会在另一个正在等待它的线程上永远等待。
在第二种情况下,我根本看不出第二个同步块的意义是什么。
wait() 的文档说
"当前线程必须拥有此对象的监视器。线程释放此监视器的所有权并等待,直到另一个线程通过调用 notify 方法或 notifyAll 方法通知等待在此对象的监视器上的线程唤醒。线程然后等待直到它可以重新获得监视器的所有权并恢复执行,”
所以我认为第二种情况是正确的,但我可能是错的。那么我是否遗漏了什么,或者我只是遇到了一个可以很容易地从代码中删除的冗余同步块?
【问题讨论】:
-
如果您看到这样的代码(其中一些无法编译),我建议您删除并重新编写它。注意:第一次调用 notify 时,什么都不会发生,因为没有线程在等待。第二次,由于条件发生变化,您不会调用 notify,因此您的第一个线程将永远等待。
-
我(糟糕地)编辑了代码以简化它作为示例。条件的东西和不可编译的错误是我,而不是代码/问题本身。此外,条件在其他地方由另一个线程更新。代码的基本 jist 是等待另一个线程完成的线程被通知条件已更改。然后,当它完成时,它会在其他地方调用 notify。
-
为什么不重写它以使用 Futures 以便知道线程何时完成?
-
a) 因为我将它移植到 C++,而不是维护当前的 Java 代码,并且 b) 即便如此,“完整”对我来说还是用词不当。等待和通知在这里实际上取决于内部状态,而不是任何实际的计算输出。
-
期货不仅仅用于计算。 C++ 也有未来和承诺。
标签: java wait synchronized reentrancy