Search code examples
javalockingmutexrace-conditionreentrantlock

What happens if we call condition.await() multiple times by the current thread in Java


I would like to understand what really happens when we execute the following code snippet.

When a thread is executes the someMethod() and hits the while loop, what happens if it calls the await method again and again? How is the thread context stored/maintained by the Condition/ReentrantLock?

Also, once a threads call await(), it means that it releases the current lock and enters into waiting state. Does that mean another thread can acquire the lock? If so, what is the use of writing a while loop around the await() method?

Lock lock = new ReentrantLock();
Condition condition = lock.newCondition();
...
...
    public void someMethod() {
        lock.lock();
        try {
            for (int i = 2; i < n; i = i + 2) {
                while (state != 2) {
                    condition.await();
                }
                printNumber.accept(i);
                r.run();
                state = 0;
                condition.signalAll();
            }
        } finally {
            lock.unlock();
        }
    }

Please correct me if my understanding is wrong. Thanks in advance.


Solution

  • The point of that wait loop apparently is to wait until the state is 2. Waking up from an await call just means you've woken up. It does not mean that the state is 2.

    The logic is the same as when I wait up in the middle of the night, look at the clock, and decide to go back to sleep. :-)

    Note the documentation for Condition notes explicitly that spurious wakeups can happen. This implies that any use of Condition.await that does not check for the actual desired state almost certainly has a bug.

    Meanwhile this code seems flawed. You know you're not going to execute the signalAll call while the thread is waiting in await, right? Because the thread is waiting in await. There needs to be some other thread, executing different code, that can signal the condition so as to get this thread out of its wait.


    Your question:

    I would like to understand what really happens when we execute the following code snippet.

    With the code shown, the thread sits in the await call forever, because no code is shown that can wake it up.

    (Per the documentation, there is the possibility of a spurious wakeup, and if that happens, the while-loop puts the thread right back into the wait, because what is being waited for won't have changed.)

    With respect to 'calling await again and again' - well, you can't call await when you're waiting - because you're in no place to call anything while you're not running. So there's no difference between the first and subsequent calls. in each case, the calling thread goes to sleep until the condition is subsequently signaled.

    As regards locking - the lock is released while waiting, and reacquired on wakeup. This is a practical necessity; presumably in your example, the lock is protecting access to 'state', and any code that wants to modify state and wake up the waiter had better do so under protection of the lock.