HuntExams Academy logo
JavaAdvanced#concurrency

Explain wait(), notify() and notifyAll().

Answer

Object methods used for inter-thread communication. wait() releases the monitor and pauses the thread. notify() wakes one waiting thread, notifyAll() wakes all. Must be called inside a synchronized block.

Example

synchronized (lock) {
  while (!ready) lock.wait();
  // proceed once notified
}
// on the other thread:
synchronized (lock) { ready = true; lock.notifyAll(); }

Detailed explanation

wait(), notify(), and notifyAll() are methods of java.lang.Object used for coordination between threads through an object's intrinsic monitor. They let a thread suspend execution until shared state may satisfy a required condition, instead of repeatedly polling. The calling thread must own the monitor of the exact object on which it invokes the method, normally through synchronized (lock) or an appropriate synchronized method. Otherwise, Java throws IllegalMonitorStateException. Merely being inside some synchronized block is not sufficient if it locks a different object.

When a thread calls lock.wait(), it enters that object's wait set and releases its monitor, allowing another thread to acquire the lock and change the shared state. It does not release any other monitors it owns. A waiting thread can leave the wait set because of notification, interruption, a timeout for timed waits, or a spurious wakeup. Before wait() returns or throws InterruptedException, the thread must reacquire the same monitor. Consequently, notification does not mean immediate execution: the awakened thread still competes for the lock.

lock.notify() selects one thread from that object's wait set, with no guaranteed selection order. lock.notifyAll() wakes all threads in that wait set, but they reacquire the monitor one at a time. Neither method releases the notifier's lock; release happens when the relevant synchronized execution exits. The usual pattern is synchronized (lock) { while (!ready) lock.wait(); /* proceed */ }, paired with synchronized (lock) { ready = true; lock.notifyAll(); }. Accesses to ready must follow the same locking protocol; releasing and subsequently acquiring that monitor provides visibility of earlier writes.

Interviewers expect you to explain why the condition check uses while rather than if: spurious wakeups are possible, and another thread may invalidate the condition before the awakened thread reacquires the monitor. Prefer notifyAll() when different conditions share a wait set, because notify() may select a thread whose condition remains false and leave useful waiters asleep. Handle interruption deliberately, usually by propagating InterruptedException or restoring the interrupt flag when propagation is inappropriate. In production, BlockingQueue, CountDownLatch, or Lock with Condition often express coordination more clearly.

Key points to remember

  • These Object methods coordinate threads through the receiver object's monitor and wait set.
  • The caller must own that exact object's monitor; otherwise IllegalMonitorStateException is thrown.
  • wait() releases the receiver's monitor and must reacquire it before returning or throwing InterruptedException.
  • notify() selects one waiter; notifyAll() wakes all waiters, without immediately releasing the notifier's monitor.
  • Always wait in a condition-checking loop and protect the shared condition with consistent synchronization.

Common mistakes candidates make

  • Calling wait() or notify() while synchronized on a different object.
  • Using if instead of while, or treating notification as proof that the condition is satisfied.
  • Assuming notification transfers the lock immediately or that wait() releases every lock the thread holds.

Likely follow-up questions

How is wait() different from Thread.sleep()?

wait() requires ownership of the receiver's monitor and releases that monitor while waiting. Thread.sleep() pauses the current thread without releasing any monitors and does not require monitor ownership.

Can a notification be lost?

Notifications are not stored as permits: notifying when no thread is waiting has no lasting effect. Protecting a persistent condition with the same monitor lets a later thread see that it can proceed without waiting.

When is notify() appropriate instead of notifyAll()?

notify() can be appropriate when all waiters await the same condition and enabling one waiter is sufficient, provided the protocol guarantees progress. With multiple conditions on one monitor, notifyAll() is generally safer, although it can cause unnecessary wakeups and lock contention.

Interview tip: Explain monitor ownership first, walk through the ready-flag example, and finish with why while and interruption handling are essential.

Related Interview Questions

1
JavaAdvanced#design-patterns

What is the Singleton pattern? How to implement it thread-safely?

Open
2
JavaIntermediate#design-patterns#spring

What is dependency injection?

Open
3
JavaBeginner#exceptions

What is the difference between throw and throws?

Open