Confusing reason for thread waking up when condition does not hold



I am currently reading Effective Java and I am on the concurrency chapter. While explaining reasons a thread might wake up when a condition doesn’t hold (condition of while loop in which a wait() call abides) there is one reason that is pretty confusing to me and I can’t seem to understand it.

Another thread could have obtained the lock and changed the guarded state between the time a thread invoked notify and the waiting thread woke up.

Can someone try to explain this sentence?

Answer

This is easiest to explain with an example:

public class ConditionTest implements Runnable {
    
    private boolean flag;
    
    public void run() {
        try {
            synchronized (this) {
                while (true) {
                    this.wait();
                    if (flag) {
                        System.out.printf("%s: my condition is truen",
                                          Thread.currentThread().getName());
                        flag = false;
                    } else {
                        System.out.printf("%s: my condition is false!!n",
                                          Thread.currentThread().getName());
                    }
                }
            }
        } catch (InterruptedException ex) {
             // bail out
        }
    }
    
    public static void main(String[] args) throws InterruptedException {
        ConditionTest ct = new ConditionTest();
        new Thread(ct).start();
        new Thread(ct).start();
        new Thread(ct).start();
    
        Thread.sleep(1000);
    
        while (true) {
            synchronized(ct) {
                ct.flag = true;
                ct.notifyAll();
            }
            Thread.sleep(1000);
        }
    }
}

The condition in this example is that the runnable’s flag should be true. The worker threads report the state of the condition and then clear the flag.

As you can see, the main method created and starts three threads sharing a runnable. Then it repeatedly sets the flag to true and notifies the workers.

When a worker is woken, it may find that the flag is false; i.e. its condition does not hold. In fact, if you run the above code, you will see that it happens two times out of three.

Why?

Because, if a worker sees that flag == true, it clears the flag! So when the other workers wake up, they see the cleared flag.

This is the kind of thing that the quoted text is talking about.

Admittedly, in this case it is caused by our dubious notifyAll call, but the general principle applies. You should check the condition.


It also is (or was) possible on some platforms for spurious notifications to happen; i.e. notifications that are not the result of any notify or notifyAll call from application code.



Source: stackoverflow