[英]Java Threading: Unexpected behavior when providing timeout argument in lock.wait()
不幸的是,由于周围的代码过于复杂,因此我无法提供完整的上下文信息。 简短的是:
我有一段等待锁的代码:
synchronized (lock) {
lock.wait();
}
哪个按预期工作。 非常简单-它获取锁,在等待开始时释放它,另一个线程获取锁,然后通知它。
但是,一旦提供超时,行为就会完全改变。
synchronized (lock) {
lock.wait(60000L);
}
同样,它应该非常简单(这可以在代码的其他几个地方按预期工作)。 但是,在这种情况下,执行基本上会暂停,直到发生超时为止。 关于发生的事情,我的唯一猜测是进入等待状态时不会释放锁-通知程序永远无法获取锁,因此等待会一直休眠直到超时。 更糟糕的是,这是一个阻塞性的睡眠-没有其他线程能够等待锁,这将强制执行完全同步。
有人对这里可能发生的事情有任何想法吗? 这是一个相当简单的功能,嵌套同步块在任何时候都没有发生任何奇怪的事情。 考虑到不提供任何超时,它应该无限期地等待,如果通知程序本身被破坏,代码将永远挂起,但事实并非如此。 只有在提供超时后,它才会停止工作。
任何想法将不胜感激。
作业系统: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()ing线程仍必须重新获取该锁:线程A等待条件变为真,线程B使条件变为真并调用notify(); 不能保证线程C不会首先获得该锁,并且在wait()调用能够返回之前再次使条件变为假。
同样,即使没有通知对象,也允许wait()返回(这称为“虚假唤醒”)。
在代码中明确要等待的条件(即count> 0)。
除了在用于wait()和notify()调用的同一锁对象上同步时,什么都没有改变要等待的条件。
不管您是否提供超时,对象上的wait方法都将释放当前线程在对象上持有的锁(如John所评论)。
使用您提供的代码并基于对场景的描述,我想是在执行lock.wait(60000L)的那一刻,JVM释放了对象上的锁,同时可能拾取处于运行/运行状态的任何其他线程如果它们在同一个对象上进行同步,则它们可能在通知程序线程获得该锁定之前就获得了锁定。
此行为很难调试,因为它取决于JVM分析器来选择应运行的线程。 因此,正如您在执行lock.wait(60000L)时所解释的那样,不必总是使通知程序线程单独承担对公共对象的锁定。 如果还有其他线程也在公共对象上等待,那么它很可能最终获得锁定,从而导致通知程序线程无法获得锁定,因此lock.wait(60000L)超时。
每当使用lock.wait(..)时 ,都必须使用lock.notify()或lock.notifyAll() 。 确保使用在逻辑上有意义的位置,并且它将在超时之前 “唤醒”锁(考虑您放置的超时值就足够了)。 这里是有关其用法的一些指南,我希望它有用: http : //www.javamex.com/tutorials/wait_notify_how_to.shtml
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.