不幸的是,我无法提供完整的上下文,因为周围的代码太复杂了。其缺点是:
我有一段代码正在等待锁:
synchronized (lock) {
lock.wait();
}
按预期工作。相当简单——它获取锁,在开始等待时释放锁,另一个线程获取锁,然后通知它。
但是,一旦我提供超时,行为就会完全改变。
synchronized (lock) {
lock.wait(60000L);
}
同样,应该相当简单(并且这在代码中的其他几个地方按预期工作)。然而,在这种情况下,执行基本上会停止,直到发生超时。我对似乎发生的事情的唯一猜测是,当它进入等待时,它不会释放锁——通知程序永远无法获取锁,因此等待会 hibernate 直到超时。更糟糕的是,这是一个阻塞 sleep - 没有其他线程能够等待该锁,并且它强制执行完全同步。
有人对这里可能发生的事情有任何想法吗?这是一个相当简单的函数,并且嵌套同步块(synchronized block)在任何时候都不会发生任何奇怪的事情。考虑到不提供超时,它应该无限期地等待,如果通知程序本身被破坏,代码将永远挂起,但事实并非如此。一旦提供超时,它就会停止工作。
任何想法将不胜感激。
操作系统:OS X 10.8.5
JDK:1.6.0、1.7.0.45 和 1.7.0.67
最佳答案
您的示例未显示 wait() 调用周围的 while() 循环。这表明您可能不完全理解等待和通知的用例。这是一个例子:
// This object is used to synchronize *EVERY* method
// that can change the value of count.
final Object lock = new Object();
int count;
void waiter() {
synchronized(lock) {
while(count <= 0) {
lock.wait();
}
//do something that you are only allowed to do
//when count > 0.
}
}
void notifier() {
synchronized(lock) {
count++;
if (count >= 0) {
lock.notify();
}
}
}
[编辑:添加了这一段,感谢 Nathan Hughes 提醒我...] wait() 调用处于循环中,因为 wait() 线程在锁被释放后仍然必须重新获取锁。 notified:如果线程A正在等待条件成立,而线程B使条件成立并调用notify();无法保证线程 C 不会首先获得锁,并在 wait() 调用返回之前再次使条件为 false。
此外,即使没有通知对象(这称为“虚假唤醒”),wait() 也可以返回。
要等待的条件在代码中是明确的(即 count > 0)。
除非在用于 wait() 和 notification() 调用的同一个锁对象上进行同步,否则不会改变等待条件。
关于Java 线程 : Unexpected behavior when providing timeout argument in lock. wait(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25209599/