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.
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(), ornotifyAll()on an object if you hold that object's monitor lock. Otherwise, the JVM throws anIllegalMonitorStateException. - Loop Condition (Crucial): Always call
wait()inside awhileloop, never anifstatement. 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 theWAITINGstate. Callingnotify()transitions one waiting thread to theBLOCKEDstate, 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.