What is the difference between notify() and notifyAll() in Java?
Both notify() and notifyAll() are Object methods that wake threads suspended in wait() on the same object's monitor. The critical difference is how many threads they wake.
notify() wakes exactly one thread from the wait set. The JVM chooses which thread arbitrarily — there is no fairness guarantee. The notified thread does not immediately execute; it must re-acquire the monitor lock (competing with all other threads that want it), then re-check its condition before proceeding.
notifyAll() wakes all threads in the wait set. They all compete to re-acquire the monitor. One wins, re-checks its condition, proceeds if satisfied, releases the lock. The others proceed one at a time in an undefined order, each re-checking its condition.
notify() is safe only when two strict conditions hold: (1) all waiting threads are identical — they wait on the same condition and perform the same action upon waking, and (2) only one thread needs to be activated per notification. If different threads wait on different conditions (e.g., some threads wait for 'buffer not full' and others for 'buffer not empty'), notify() may wake the wrong type of thread, which re-evaluates its condition, finds it unsatisfied, and calls wait() again — while the thread that should have been notified never wakes up. This is the classic missed wakeup / deadlock scenario.
notifyAll() is the safe default. The cost is thundering herd: many threads wake, compete for the lock, find their condition unsatisfied, and go back to sleep. For performance-critical code with many waiting threads and high throughput, this can be measurable.
The modern solution is java.util.concurrent.locks.Condition, which supports multiple condition queues per lock. In a producer-consumer pattern, you maintain a notFull and notEmpty Condition separately — signal() on notFull wakes only producer threads, signal() on notEmpty wakes only consumer threads. This gives the precision of notify() without the correctness risk.
| Aspect | notify() | notifyAll() |
|---|---|---|
| Threads woken | One (arbitrary) | All in the wait set |
| Correctness | Only safe if all waiters are identical | Safe in all cases |
| Risk | Missed wakeup if wrong thread chosen | Thundering herd (performance) |
| Performance | Lower overhead, one wake | Higher overhead with many waiters |
| When to use | Single-condition wait set, identical waiters | Multiple conditions or heterogeneous waiters |
| Modern alternative | Condition.signal() | Condition.signalAll() |
Correctly states notify() wakes one thread arbitrarily and notifyAll() wakes all, and identifies the missed wakeup risk with notify() when waiters have different conditions.
Explains the two conditions under which notify() is safe, describes the thundering herd issue with notifyAll(), and mentions Condition.signal()/signalAll() as the modern solution with separate wait queues.
Reading the answer is step one. Explaining it unprompted — under interview pressure — is what actually matters. Get AI-graded feedback on your answer with follow-up probes on your weak points.
Get Graded — Free Assessment