What is a spurious wakeup, and what coding discipline does it force on every use of wait()?
answer
- Spurious = woke with no notify
- Allowed by the JLS / Javadoc — must tolerate it
- Always while, never if, around wait()
- Loop also covers stale notifications (another waiter consumed it)
- Condition.await() needs the same loop
basics
~20 sA spurious wakeup is when a thread returns from wait() even though nobody called notify() or notifyAll(). Because it can happen, you must always call wait() inside a while loop that re-checks the condition, so the thread only proceeds when the condition is actually true — never inside a plain if.
solid answer
~50 sA spurious wakeup is a wakeup from wait() that occurs without any corresponding notify/notifyAll — the JVM and underlying OS are explicitly permitted to do this for implementation efficiency, so you cannot assume that returning from wait() means your condition is now true. The mandated discipline is to wrap wait() in a while loop that re-evaluates the guard: `while (!condition) lock.wait();`. On any wakeup — spurious or real — the thread re-checks the predicate and goes back to waiting if it's still false. An if would let a spuriously woken thread fall through and operate on an invalid state. The same loop also handles the legitimate case where a real notify woke several threads but an earlier one already consumed the condition, so the guarded-loop idiom is required regardless. This is why the Object.wait Javadoc itself shows wait inside a while loop.
go deeper
Recognizes the term and that you should use a while loop with wait(), even if hazy on why.
Defines a spurious wakeup as a wakeup without a notify, knows the JLS permits it, and consistently uses while not if.
Distinguishes spurious wakeups from stale notifications, explains both motivate the same loop, and applies it to Condition.await() too.
Traces the behavior to OS condition-variable semantics, reasons about why the JVM doesn't suppress it, and standardizes guarded-wait idioms or higher-level constructs across a codebase.
## Definition A **spurious wakeup** is when a thread blocked in `Object.wait()` (or `Condition.await()`, or even `Thread.sleep` semantics in some libs) **returns as if notified, but no `notify()` / `notifyAll()` actually occurred**. The Java Language Specification and `Object.wait`'s Javadoc explicitly allow this: the runtime is *not required* to guarantee that a wakeup corresponds to a real signal. It stems from how condition-variable primitives are implemented on top of OS facilities (e.g. POSIX `pthread_cond_wait` is documented to allow spurious returns), and the JVM passes that permission through rather than paying to suppress it. ## Why it matters If you assume 'I returned from `wait()`, therefore my condition is satisfied,' a spurious wakeup breaks that assumption: the thread proceeds with the guard still false, leading to corrupted state, exceptions (e.g. removing from an empty queue), or subtle logic errors. ## The forced discipline: guarded loop Always structure waiting as: ```java synchronized (lock) { while (!conditionHolds()) { // re-check on EVERY wakeup lock.wait(); } // safe: conditionHolds() is true AND we hold the lock doWork(); } ``` - **`while`, never `if`.** With `if`, a single spurious (or stale) wakeup falls straight through to `doWork()` with the condition possibly false. With `while`, the thread re-tests the predicate and loops back to `wait()` if it isn't yet true. - This is non-negotiable: the JLS effectively *requires* applications to tolerate spurious wakeups, so the loop is not optional defensive coding — it is the contract. ## Two reasons the loop is needed (not just one) 1. **Spurious wakeups** — wakeups with no signal at all. 2. **Stale notifications** — a *real* `notifyAll()` woke several waiters, but by the time this thread re-acquires the lock, an earlier-woken thread already consumed the condition (e.g. took the only item). The guard is now false again. The same `while` loop covers this case too. So even if spurious wakeups didn't exist, multi-waiter scenarios would still demand the loop — which is why 'always loop' is the universal rule. ## The modern equivalent `Condition.await()` (on `ReentrantLock`) has the **identical** requirement — it may also wake spuriously, so it too must be called in a `while` loop. Higher-level utilities like `BlockingQueue` hide all of this from you, which is one reason to prefer them. ## One-line takeaway Returning from `wait()` means 'you might be able to proceed — re-check' not 'you may proceed.' The `while` loop encodes exactly that.
- Even without spurious wakeups, why would the while loop still be necessary?Because of stale notifications: a notifyAll can wake several threads, but an earlier one may consume the condition before this thread re-acquires the lock, so the guard must be re-checked.
- Does Condition.await() on a ReentrantLock also suffer spurious wakeups?Yes. Its Javadoc states it may return spuriously, so await() must likewise be called inside a while loop re-checking the predicate.
saying these in an interview costs you the question
- Guarding wait() with if instead of while
- Assuming a return from wait() guarantees the condition is true
- Claiming spurious wakeups are a JVM bug rather than a permitted behavior
- Thinking Condition.await() is immune to spurious wakeups
- Re-checking the condition outside the synchronized region