1. The Hook (The "Byte-Sized" Intro)
- In a Nutshell: Inter-thread communication allows threads to coordinate via wait(), notify(), and notifyAll()—methods from Object class (not Thread!). wait() releases lock and waits until notified. notify() wakes one waiting thread. notifyAll() wakes all. Must be called inside synchronized block or get IllegalMonitorStateException.
- Classic pattern: Producer-Consumer—producer creates items, consumer processes them, both coordinate via wait/notify.
Think of restaurant: Chef (producer) cooks food, waiter (consumer) serves it. Chef signals "Order up!" (notify). Waiter waits if no food ready (wait). Perfect coordination!
2. Conceptual Clarity (The "Simple" Tier)
💡 The Analogy: The Parking Lot
- wait(): Park car, leave keys with attendant (release lock), sleep in waiting room
- notify(): Attendant wakes you up "Your turn!"
- notifyAll(): Attendant announces "Everyone check if it's your turn!"
3. Technical Mastery (The "Deep Dive")
Producer-Consumer Pattern
java
class SharedQueue {
private Queue<Integer> queue = new LinkedList<>();
private final int MAX_SIZE = 5;
public synchronized void produce(int item) throws InterruptedException {
while (queue.size() == MAX_SIZE) {
wait(); // Wait if queue full
}
queue.add(item);
System.out.println("Produced: " + item);
notifyAll(); // Notify consumers
}
public synchronized int consume() throws InterruptedException {
while (queue.isEmpty()) {
wait(); // Wait if queue empty
}
int item = queue.poll();
System.out.println("Consumed: " + item);
notifyAll(); // Notify producers
return item;
}
}4. Interactive & Applied Code
java
import java.util.*;
class SharedBuffer {
private List<Integer> buffer = new ArrayList<>();
private final int CAPACITY = 3;
public synchronized void produce(int value) throws InterruptedException {
// ALWAYS use while, not if (spurious wakeups!)
while (buffer.size() == CAPACITY) {
System.out.println("Buffer full, producer waiting...");
wait(); // Releases lock!
}
buffer.add(value);
System.out.println("Produced: " + value + " | Buffer: " + buffer);
notifyAll(); // Wake up consumers
}
public synchronized int consume() throws InterruptedException {
while (buffer.isEmpty()) {
System.out.println("Buffer empty, consumer waiting...");
wait();
}
int value = buffer.remove(0);
System.out.println("Consumed: " + value + " | Buffer: " + buffer);
notifyAll(); // Wake up producers
return value;
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
SharedBuffer buffer = new SharedBuffer();
// Producer thread
Thread producer = new Thread(() -> {
try {
for (int i = 1; i <= 10; i++) {
buffer.produce(i);
Thread.sleep(100);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Producer");
// Consumer thread
Thread consumer = new Thread(() -> {
try {
for (int i = 1; i <= 10; i++) {
buffer.consume();
Thread.sleep(300); // Slower than producer
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}, "Consumer");
producer.start();
consumer.start();
}
}5. The Comparison & Decision Layer
| Method | What it Does | When to Use |
|---|---|---|
| wait() | Release lock, wait for notification | Condition not met |
| notify() | Wake one thread | Single consumer/producer |
| notifyAll() | Wake all threads | Multiple consumers/producers |
6. The "Interview Corner" (The Edge)
The "Killer" Interview Question: "Why must wait() be called in a while loop, not if?" Answer: Spurious wakeups! Thread can wake up WITHOUT notify():
java
// ❌ BAD: Use if
if (queue.isEmpty()) {
wait(); // Wakes up spuriously
}
queue.poll(); // ❌ Might still be empty!
// ✅ GOOD: Use while
while (queue.isEmpty()) {
wait(); // Re-checks condition after waking
}
queue.poll(); // ✅ Guaranteed non-emptyAlso prevents "lost notification"—if notified before checking, while re-checks!
Pro-Tip: notify() vs notifyAll():
java
// ✅ Use notify() when:
// - All threads wait for same condition
// - Only one thread can proceed
notify(); // Wakes one arbitrary thread
// ✅ Use notifyAll() when:
// - Multiple different conditions
// - Multiple threads can proceed
notifyAll(); // Wakes all, they re-check conditionsWhen in doubt, use notifyAll() (safer but slightly less efficient).