I have been playing with my own version of this, using \'if\', and all seems to be working fine. Of course this will break down horribly if signalAll() is used instead of s
The main reason for this is that when a thread is notified it can't act right away, it has to acquire the lock first. And there is no guarantee it will be the next thread to get the lock.
When a thread receives a notification while waiting, it does not have the lock. (It released the lock when it started waiting.) Before it can leave the wait method it has to reacquire the lock. It has no priority over any other thread contending for the lock, it is entirely likely some other thread may get there first.
Whatever those intervening threads do could change the state of the object being accessed, possibly making the notification irrelevant. So once the notified thread has successfully reacquired the lock, it needs to check the condition again in order to verify that the condition that it was notified about is still actually true. The while loop is there so that the thread can check the condition again once it has the lock.
In addition to that there are other reasons to use a while loop for check that the condition you're waiting for is present:
It's not valid to infer from your thread having stopped waiting that it necessarily must have gotten notified; this is the "spurious wakeup".
Also if there are multiple things that a notification could mean, then you'd want to check the condition again in order to make sure the event you're interested in was what you were woken up for.