Knowledge Guide
HomeConcurrencyConcurrency Foundations

Condition Variables — wait, notify & the while-loop trap

Waiting efficiently for a condition

A worker often must wait until some state is true — a queue is non-empty, a connection is ready. Spinning in a loop burns a CPU. A condition variable lets a thread release the lock and sleep until another thread signals that the state changed, then wake and re-check. In Java this is Object.wait()/notify() (or Condition.await()/signal()).

A thread calls wait(), releases the monitor lock and moves to the wait-set; notify() moves it back to re-acquire the lock and re-check the condition
A thread calls wait(), releases the monitor lock and moves to the wait-set; notify() moves it back to re-acquire the lock and re-check the condition

The mechanism

Inside a synchronized block, wait() atomically releases the lock and parks the thread in the monitor's wait-set. Another thread takes the lock, changes state, and calls notify(), moving a waiter back to compete for the lock. When the waiter re-acquires it, wait() returns — and it must re-check the condition.

The #1 bug: if instead of while

// BROKEN
synchronized (q) {
    if (q.isEmpty()) q.wait();   // wakes up -> assumes non-empty -> may be wrong
    return q.remove();           // throws if another consumer already drained it
}
// CORRECT
synchronized (q) {
    while (q.isEmpty()) q.wait(); // re-check after every wakeup
    return q.remove();
}

Why while is mandatory: spurious wakeups (the JVM may wake a waiter for no reason) and stale wakeups (another consumer grabbed the item between notify and your re-acquire). Re-check, always.

notify vs notifyAll

notify() wakes one arbitrary waiter; notifyAll() wakes all. Use notifyAll() unless every waiter is waiting on the identical condition — otherwise you risk a lost wakeup (you wake a thread whose condition still isn't satisfied while the right one sleeps on).

In Go: channels instead

Go rarely uses condition variables (sync.Cond exists but is uncommon). The idiom is to wait on a channel — a receive blocks until a sender signals, and select waits on several conditions at once. The bounded buffer is just a buffered channel; "wait until non-empty" is "receive from the channel":

items := make(chan Item, 100)   // buffered = bounded buffer
go func(){ items <- produce() }()   // producer
it := <-items                       // consumer blocks until an item exists — no wait/notify, no while-loop bug

That's the CSP payoff: the channel is the condition variable, with the re-check designed away.

Takeaways


Re-authored for this guide; monitor/wait-set diagram hand-authored as SVG. Follows Java Concurrency in Practice ch. 14 and The Little Book of Semaphores. See also: Semaphores, Producer-Consumer, Go Concurrency.

🤖 Don't fully get this? Learn it with Claude

Stuck on Condition Variables — wait, notify & the while-loop trap? Open Claude, copy a block below, and it'll teach you this exact concept — visually and interactively.

🎨 Explain it visually

Build the mental picture, not memorization.

I just read a lesson on **Condition Variables — wait, notify & the while-loop trap** (Concurrency) and want to truly understand it. Explain Condition Variables — wait, notify & the while-loop trap from first principles using ONE vivid real-world analogy and a visual mental model — draw it as ASCII art or a clear step-by-step diagram — with a concrete example using real numbers. Then ask me one question to check I got the mental picture, and wait for my reply. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🤔 Walk me through it (interactive)

Socratic — adapts to where you're stuck.

Teach me **Condition Variables — wait, notify & the while-loop trap** interactively. Ask me ONE guiding question at a time, wait for my answer, and adapt to my confusion — build the idea with me step by step instead of explaining it all at once. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧪 Quiz me & fix my gaps

Active recall exposes what you missed.

Quiz me on **Condition Variables — wait, notify & the while-loop trap** with 5 questions, easy to tricky, ONE at a time. Tell me if each answer is right; at the end, explain clearly what I got wrong and why. If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.
🧠 Make it stick

Intuition + hook + flashcards for long-term memory.

Help me remember **Condition Variables — wait, notify & the while-loop trap** for the long term: give the one-sentence intuition, a memorable hook/mnemonic, a tiny worked example, and 3 active-recall flashcards (Q -> A). If you're unsure or a claim isn't standard, say so and reason from first principles instead of guessing.

📝 My notes