ReviseAlgo Logo

Multithreading

Inter-Thread Communication

Coordinate threads using wait(), notify(), and notifyAll() inside synchronized blocks.

Interview: Frequently tested through practical synchronization challenges, such as implementing a thread-safe Producer-Consumer pattern or Bounded Queue.

Last Updated: June 13, 2026 12 min read

Inter-thread communication allows threads to coordinate work. The wait(), notify(), and notifyAll() methods of the Object class allow threads to yield locks and wait for changes.

Core Idea

A thread calls wait() to temporarily yield a lock and block until another thread calls notify() or notifyAll() on that same object.

Why It Matters

Using wait/notify is more efficient than busy-waiting loops (polling), which consume 100% CPU cycles.

Interview Lens

Expect design challenges where you must write a Bounded Queue using wait() and notifyAll() inside a while loop.

API Contract and Guidelines

You must follow these rules when using these APIs:

  • Synchronized Context: You can only call wait(), notify(), or notifyAll() on an object if you hold that object's monitor lock. Otherwise, the JVM throws an IllegalMonitorStateException.
  • Loop Condition (Crucial): Always call wait() inside a while loop, never an if statement. This protects against spurious wakeups (where a thread wakes up without being notified) and race conditions where state changes before the thread resumes.
  • State Transition: Calling wait() releases the lock and transitions the thread to the WAITING state. Calling notify() transitions one waiting thread to the BLOCKED state, waiting to acquire the lock when the caller releases it.

Code Walkthrough

Here is a complete, thread-safe implementation of a 1-capacity Bounded Buffer (Producer-Consumer).

public class SharedBuffer {
    private String data;
    private boolean empty = true;

public synchronized void produce(String item) throws InterruptedException { // Always check condition in a loop while (!empty) { wait(); // Releases lock, enters WAITING } data = item; empty = false; System.out.println("Produced: " + item); notifyAll(); // Wake up waiting consumers }

public synchronized String consume() throws InterruptedException { while (empty) { wait(); } String item = data; empty = true; System.out.println("Consumed: " + item); notifyAll(); // Wake up waiting producers return item; } }

Interview-Relevant Information

Q: Why is notifyAll() preferred over notify()?
Answer: notify() wakes up exactly one thread chosen arbitrarily by the JVM. notifyAll() wakes up all waiting threads. If multiple threads are waiting, calling notify() can wake up a thread that cannot make progress, leading to a deadlock where all threads wait forever.

Quick Checklist

Why must wait() be inside a while loop? Why does calling notify() not release the lock immediately? If yes, you understand inter-thread communication.

Use Cases

Implementing custom coordination patterns or custom blocking queues.

Coordinating multi-stage batch processing pipelines.

Common Mistakes

Calling wait() without holding the object monitor, throwing IllegalMonitorStateException.

Using notify() instead of notifyAll() when multiple threads are waiting, which can lead to deadlocks.