🔔 notify()
vs notifyAll()
— Core Idea
notify()
- Wakes up one random thread that’s waiting on the same object’s monitor (lock).
- It’s not guaranteed which thread will be woken if multiple are waiting.
- Only one continues; the others remain waiting.
notifyAll()
- Wakes up all threads that are waiting on the object’s monitor.
- But remember: only one of them can acquire the lock and proceed.
- The rest go back to waiting until it’s their turn.
🔄 Example to Visualize It
Let’s say 3 threads are waiting on a lock:
synchronized (lock) {
lock.wait(); // Thread A
}
synchronized (lock) {
lock.wait(); // Thread B
}
synchronized (lock) {
lock.wait(); // Thread C
}
Then:
🔔 If you call lock.notify();
- Only one thread (say, Thread B) will wake up and try to acquire the lock.
- A and C remain in waiting state.
🔔 If you call lock.notifyAll();
- All threads (A, B, and C) are notified.
- But only one can acquire the lock, others keep waiting until the lock is available.
📌 Summary Table
Feature | notify() | notifyAll() |
---|---|---|
Wakes how many? | 🔸 One thread | 🔹 All waiting threads |
Thread chosen? | Random, not under your control | All woken, one proceeds |
Performance | More efficient (but risky) | Slightly heavier (but safer) |
Risk | Some threads may starve | All get a chance eventually |
Usage | When only one needs to proceed | When multiple threads may be eligible |
✅ When to Use What?
Use notify()
:
- When only one thread should proceed at a time, and it’s okay if others wait.
- Example: one producer, one consumer.
Use notifyAll()
:
- When multiple threads may be able to proceed, or you can’t predict which should.
- Example: many threads waiting for a condition — safest to wake all.
🚨 Be Careful!
If you use
notify()
in a system with multiple consumers or producers, it may wake the wrong thread, leading to deadlocks or inefficiency.
That’s why notifyAll()
is often the default safe choice in more complex systems.
🎯 The Risk: Waking a Thread That Can’t Proceed
When you use notify()
, only one thread is woken — and you don’t control which one.
If that thread can’t do anything yet (its condition isn’t true), it will:
- Wake up,
- Re-check the condition (in the
while
loop), - Go back to waiting.
Meanwhile, other threads that could have made progress remain stuck in waiting state 😬
🧪 Real Example: Multiple Consumers
Let’s say:
- You have one producer
- You have three consumers waiting for a task
- But only one task is currently available: a task that only Consumer B can handle
Now:
- Producer does:
synchronized (lock) {
// adds task
lock.notify();
}
- If the JVM chooses Consumer A or C, and they can’t process that task, they’ll just go back to waiting
❗ Problem:
- Nobody handles the task!
- The thread that could do the job (Consumer B) is still waiting 😭
This can lead to:
- Deadlocks
- Starvation
- Wasted CPU cycles
✅ How notifyAll()
Solves This
If you write:
synchronized (lock) {
// adds task
lock.notifyAll();
}
Then:
- A, B, and C are all woken up
- They each check:
- “Is this task for me?”
- Only B proceeds, others go back to
wait()
This guarantees that:
- Whoever can proceed, will proceed
- No one is accidentally left out
🎯 Summary: Why notify()
is Risky
Risk | Description |
---|---|
Wrong thread wakes up | Woken thread may not be able to proceed |
Others stay sleeping | Threads that could act remain blocked |
Leads to inefficiency | CPU wasted, notifications lost, progress delayed |
Can cause deadlocks | If no thread can proceed but all are waiting for someone to act |
🔐 Rule of Thumb:
Use
notifyAll()
when multiple threads are waiting for different conditions.
Usenotify()
only when you’re 100% sure that any waiting thread can safely proceed.