在while循环中等待(长超时)?

时间:2021-12-22 06:58:49

I've read that you're supposed to put Object.wait() calls in Java in a while loop. The reason is that this thread may be woken up and the condition that you were waiting to notify on is still false(spurious wake-up).

我已经读过,您应该在while循环中使用Java输入Object.wait()调用。原因是这个线程可能会被唤醒,而您等待通知的条件仍然是假的(伪唤醒)。

What about Object.wait(long timeout). Here, you don't want to loop on the condition since you want it to time out after the specified amount of time. But if you don't put it in a loop then how can you ensure that it won't be woken up early?

什么是对象。等待(长超时)。在这里,您不希望在条件下循环,因为您希望它在指定的时间之后超时。但是如果你不把它放在一个循环中,你怎么能保证它不会被提前唤醒呢?

4 个解决方案

#1


11  

But if you don't put it in a loop then how can you ensure that it won't be woken up early?

但是如果你不把它放在一个循环中,你怎么能保证它不会被提前唤醒呢?

This is a deficiency in Java IMO although maybe it's a deficiency with the underlying thread support in various OS varients. I suspect Java knows whether the wait timed out or not but there is no way for the caller to figure it out without re-testing the condition and specifically testing the time. Ugly.

这是Java IMO的一个缺陷,尽管它可能是各种OS变体中底层线程支持的缺陷。我怀疑Java知道等待是否超时,但如果不重新测试条件并具体测试时间,调用者就无法找到它。丑。

So you will need to put the wait(long timeout) in a while loop as well and also test to see if the time is past the timeout period. I know of no other way to accomplish this.

因此,您还需要将等待(长超时)放在while循环中,并测试时间是否超过超时时间。我知道没有别的办法可以做到这一点。

long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
while (!condition) {
    long waitMs = timeoutExpiredMs - System.currentTimeMillis();
    if (waitMs <= 0) {
       // timeout expired
       break;
    }
    // we assume we are in a synchronized (object) here
    object.wait(waitMs);
    // we might get improperly awoken here so we loop around to see if we timed out
}

#2


2  

long deadline = now() + timeout;

synchronized(lock)

    while( !condition() && now()<deadline )
        lock.wait( deadline - now() );

    if(condition())
        ...
    else // timeout
        ...

#3


2  

it is because java has Mesa style monitors instead of Hoare style monitors. So you need to put wait in a while loop. Please search the string "For this reason, it is usually necessary to enclose each wait operation in a loop like this" on the follwing web page,

这是因为java拥有Mesa风格的监视器,而不是Hoare风格的监视器。所以你需要在while循环中放入wait。请搜索字符串“出于这个原因,通常需要将每个等待操作包含在如下所示的循环中”

http://en.wikipedia.org/wiki/Monitor_(synchronization)#Nonblocking_condition_variables

# Nonblocking_condition_variables http://en.wikipedia.org/wiki/Monitor_(同步)

.if it had been a Hoare style monitors then you could have put your wait in if. I will soon add details of Mesa monitors. This is not deficiency in Java. Both types of monitors have advantages and disadvantages.

如果它是Hoare风格的监视器,那么你可以把你的等待放在if中。我将很快添加Mesa监视器的细节。这并不是Java的不足之处。这两种显示器各有优缺点。

#4


0  

Calling wait in a loop isn't just for handling the occasional spurious wakeup. In the general (non-toy example) case where multiple threads are contending for the lock, at the time a thread wakes up from wait any checks it made prior to waiting aren't enough to predict what state the object is in. The thread that was waiting had relinquished the lock so anything could have happened since then, and moreover there's nothing atomic about how notifications work, just because you got notified doesn't mean another thread didn't sneak in in the time between when the notification was made and the notified thread reacquired the lock.

在循环中调用wait不仅是为了处理偶尔出现的虚假唤醒。在一般的(非玩具示例)中,多个线程正在为锁争用,此时线程从等待中醒来,等待的任何检查都不足以预测对象所在的状态。是等待的线程释放锁,所以从那时起,什么事都有可能发生,而且没有什么原子如何通知工作,仅仅因为你有通知并不意味着另一个线程之间的时间没有偷偷通知时,通知线程再获得的锁。

Fundamentally you wait in a loop because you need to check the current state with the lock held, in order to be able to tell what's going on. Having a timeout doesn't change that. A timeout is a safety mechanism so that if a notification is missed the thread won't hang forever. If the wait times out there usually isn't any specific action needed, just reacquire the lock, proceed to the loop body, and check thr condition as usual.

从根本上说,您需要在循环中等待,因为您需要检查锁所持有的当前状态,以便能够知道发生了什么。超时并不会改变这一点。超时是一种安全机制,因此如果错过通知,线程就不会永远挂起。如果外面的等待时间通常不需要任何特定的操作,只需重新获取锁,继续到循环体,并像往常一样检查thr条件。

And this isn't Java's fault, this is how pthreads work.

这不是Java的错,这是pthreads的工作方式。

#1


11  

But if you don't put it in a loop then how can you ensure that it won't be woken up early?

但是如果你不把它放在一个循环中,你怎么能保证它不会被提前唤醒呢?

This is a deficiency in Java IMO although maybe it's a deficiency with the underlying thread support in various OS varients. I suspect Java knows whether the wait timed out or not but there is no way for the caller to figure it out without re-testing the condition and specifically testing the time. Ugly.

这是Java IMO的一个缺陷,尽管它可能是各种OS变体中底层线程支持的缺陷。我怀疑Java知道等待是否超时,但如果不重新测试条件并具体测试时间,调用者就无法找到它。丑。

So you will need to put the wait(long timeout) in a while loop as well and also test to see if the time is past the timeout period. I know of no other way to accomplish this.

因此,您还需要将等待(长超时)放在while循环中,并测试时间是否超过超时时间。我知道没有别的办法可以做到这一点。

long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
while (!condition) {
    long waitMs = timeoutExpiredMs - System.currentTimeMillis();
    if (waitMs <= 0) {
       // timeout expired
       break;
    }
    // we assume we are in a synchronized (object) here
    object.wait(waitMs);
    // we might get improperly awoken here so we loop around to see if we timed out
}

#2


2  

long deadline = now() + timeout;

synchronized(lock)

    while( !condition() && now()<deadline )
        lock.wait( deadline - now() );

    if(condition())
        ...
    else // timeout
        ...

#3


2  

it is because java has Mesa style monitors instead of Hoare style monitors. So you need to put wait in a while loop. Please search the string "For this reason, it is usually necessary to enclose each wait operation in a loop like this" on the follwing web page,

这是因为java拥有Mesa风格的监视器,而不是Hoare风格的监视器。所以你需要在while循环中放入wait。请搜索字符串“出于这个原因,通常需要将每个等待操作包含在如下所示的循环中”

http://en.wikipedia.org/wiki/Monitor_(synchronization)#Nonblocking_condition_variables

# Nonblocking_condition_variables http://en.wikipedia.org/wiki/Monitor_(同步)

.if it had been a Hoare style monitors then you could have put your wait in if. I will soon add details of Mesa monitors. This is not deficiency in Java. Both types of monitors have advantages and disadvantages.

如果它是Hoare风格的监视器,那么你可以把你的等待放在if中。我将很快添加Mesa监视器的细节。这并不是Java的不足之处。这两种显示器各有优缺点。

#4


0  

Calling wait in a loop isn't just for handling the occasional spurious wakeup. In the general (non-toy example) case where multiple threads are contending for the lock, at the time a thread wakes up from wait any checks it made prior to waiting aren't enough to predict what state the object is in. The thread that was waiting had relinquished the lock so anything could have happened since then, and moreover there's nothing atomic about how notifications work, just because you got notified doesn't mean another thread didn't sneak in in the time between when the notification was made and the notified thread reacquired the lock.

在循环中调用wait不仅是为了处理偶尔出现的虚假唤醒。在一般的(非玩具示例)中,多个线程正在为锁争用,此时线程从等待中醒来,等待的任何检查都不足以预测对象所在的状态。是等待的线程释放锁,所以从那时起,什么事都有可能发生,而且没有什么原子如何通知工作,仅仅因为你有通知并不意味着另一个线程之间的时间没有偷偷通知时,通知线程再获得的锁。

Fundamentally you wait in a loop because you need to check the current state with the lock held, in order to be able to tell what's going on. Having a timeout doesn't change that. A timeout is a safety mechanism so that if a notification is missed the thread won't hang forever. If the wait times out there usually isn't any specific action needed, just reacquire the lock, proceed to the loop body, and check thr condition as usual.

从根本上说,您需要在循环中等待,因为您需要检查锁所持有的当前状态,以便能够知道发生了什么。超时并不会改变这一点。超时是一种安全机制,因此如果错过通知,线程就不会永远挂起。如果外面的等待时间通常不需要任何特定的操作,只需重新获取锁,继续到循环体,并像往常一样检查thr条件。

And this isn't Java's fault, this is how pthreads work.

这不是Java的错,这是pthreads的工作方式。