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).
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?
The while loop contains the call to wait() . The wait() method waits indefinitely for a notification from the Producer thread. When the put() method calls notify() , the Consumer wakes up from the wait state and continues within the while loop.
To guarantee liveness, programs must test the while loop condition before invoking the wait() method. This early test checks whether another thread has already satisfied the condition predicate and sent a notification. Invoking the wait() method after the notification has been sent results in indefinite blocking.
wait(long timeout) causes current thread to wait until either another thread invokes the notify() method or the notifyAll() method for this object, or a specified amount of time has elapsed.
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.
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.
long timeoutExpiredMs = System.currentTimeMillis() + timeoutMs;
while (!condition) {
long waitMillis = timeoutExpiredMs - System.currentTimeMillis();
if (waitMillis <= 0) {
// timeout expired
break;
}
// we assume we are in a synchronized (object) here
object.wait(waitMillis);
// we might be improperly awoken here so we loop around to see if the
// condition is still true or if we timed out
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With