Lesson Completion
Back to course

Inter-Thread Communication: wait(), notify(), and Producer-Consumer

Advanced
25 minutes4.7Java

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

MethodWhat it DoesWhen to Use
wait()Release lock, wait for notificationCondition not met
notify()Wake one threadSingle consumer/producer
notifyAll()Wake all threadsMultiple 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-empty

Also 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 conditions

When in doubt, use notifyAll() (safer but slightly less efficient).

Topics Covered

Java FundamentalsConcurrency

Tags

#java#multithreading#threads#concurrency#parallelism

Last Updated

2025-02-01