notify() vs notifyAll() — when is it safe to use notify()? — Cracked Java
// Concurrency & Multithreading · Synchronization & Intrinsic Locks
SeniorTheoryTrick

notify() vs notifyAll() — when is it safe to use notify()?

notify() wakes one arbitrary thread from the monitor's wait set; notifyAll() wakes them all to compete for the lock. notify() is cheaper but only safe under strict conditions — most of the time you should default to notifyAll().

The risk with notify()

If multiple threads wait on the same monitor for different conditions, notify() may wake the wrong thread — one whose predicate is still false. That thread re-checks (it's in a while loop), goes back to wait(), and the thread that could have proceeded was never signaled. This is a lost wakeup: the system stalls even though progress was possible.

wait set: [Producer waiting for space, Consumer waiting for item]
state: buffer is FULL, an item was just added by... nobody yet
notify() -> wakes Producer -> still full -> re-waits
          (the Consumer who could run was not woken) -> STALL
notify() can wake the wrong waiter

When notify() is safe

You may use notify() only when all three hold:

  1. Uniform waiters — every thread waiting on the monitor is waiting for the same condition (so any one of them can validly proceed).
  2. One-in, one-out — a single notify corresponds to a single unit of progress (e.g. you produced exactly one item, so waking exactly one consumer is correct).
  3. The waking is not relied upon to chain to a different kind of waiter.

A textbook fit is a Semaphore-like resource pool where every waiter wants "a permit" and you release exactly one.

Default to notifyAll()

notifyAll() is always correct (every thread re-checks its predicate and only the eligible ones proceed); the only cost is a thundering herd — all waiters wake, contend for the lock, and most go straight back to waiting, wasting CPU. For low contention this overhead is negligible, so the safe default is notifyAll().

// Producer/consumer on one monitor with two conditions:
// producers wait on "not full", consumers wait on "not empty"
// -> waiters are NOT uniform -> notify() can lose a wakeup
// -> use notifyAll()
notifyAll();

If notify()'s overhead actually matters, the cleaner fix is to stop sharing one monitor: use a ReentrantLock with separate Condition objects (notFull, notEmpty) and signal() the right one — that gives notify-level efficiency with notifyAll-level safety.

Mark your status