views:

467

answers:

4

I have read that we should always called a wait() from within a loop:

while (!condition) { obj.wait(); }

It works fine without a loop so why is that?

+1  A: 

There might be more then just one worker waiting for a condition to become true.

If two or more worker get awake (notifyAll) they have to check the condition again. otherwise all workers would continue even though there might only be data for one of them.

Philipp
+3  A: 

Because wait and notify are used to implement condition variables and so you need to check whether the specific predicate you're waiting on is true before continuing.

Aaron Maenpaa
kd304 is correct - it is not just that a condition may not have been met - it is the fact that a thread can spuriously wake up from a wait
oxbow_lakes
@oxbow_lakes As far a the thread waiting on a condition is concerned, there is no real difference between a spurious wake-up and a notify meant to signal a different condition. Either way, you have to check your predicate.
Aaron Maenpaa
+10  A: 

You need not only to loop it but check your condition in the loop. Java does not guarantee that your thread will be woken up only by a notify()/notifyAll() call or the right notify()/notifyAll() call at all. Because of this property the loop-less version might work on your development environment and fail on the production environment unexpectedly.

For example, you are waiting for something:

synchronized (theObjectYouAreWaitingOn) {
   while (!carryOn) {
      theObjectYouAreWaitingOn.wait();
   }
}

An evil thread comes along and:

theObjectYouAreWaitingOn.notifyAll();

If the evil thread does not/can not mess with the carryOn you just continue to wait for the proper client.

Edit: Added some more samples. The wait can be interrupted. It throws InterruptedException and you might need to wrap the wait in a try-catch. Depending on your business needs, you can exit or suppress the exception and continue waiting.

kd304
This is the correct answer. The documentation for wait:http://java.sun.com/javase/6/docs/api/java/lang/Object.html#wait(long)... actually describes why you need to put it in a loop - spurious wakeups. Did the OP read it?
Andrew Duffy
Ah, 'spurious wakeups'. Could not remember the name.
kd304
You should update your code example to handle the ThreadInterruptedException on your wait. It would then be consistent with your answer.
Robin
Don't know. Adding the try-catch for InterruptedException seemed pointless as it depends on the business logic what you want to do in case of the thread interruptions. Probably you would just exit, or suppress it immediately inside the loop.
kd304
+3  A: 

It's answered in documentation for Object.wait(long milis)

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }

(For more information on this topic, see Section 3.2.3 in Doug Lea's "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, 2000), or Item 50 in Joshua Bloch's "Effective Java Programming Language Guide" (Addison-Wesley, 2001).

Tadeusz Kopec