Fundamentals 9 min read

Producer-Consumer Problem and wait()/notify() in Java

This article explains the classic producer‑consumer concurrency model, its advantages of decoupling, asynchrony and speed balancing, and demonstrates how Java’s wait(), notify() and notifyAll() mechanisms are used to coordinate producer and consumer threads with sample code implementations.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Producer-Consumer Problem and wait()/notify() in Java

The producer‑consumer problem is a classic multithreaded coordination model where producer threads generate items and place them into a queue while consumer threads remove and process those items. The queue acts as a buffer that decouples production from consumption and enables asynchronous operation.

In Java, the built‑in Object methods wait() , notify() and notifyAll() provide the notification mechanism that allows threads to cooperate: a producer waits when the queue is full, and a consumer waits when the queue is empty.

The article details how wait() releases the monitor lock and suspends the thread until another thread calls notify() (waking a single waiting thread) or notifyAll() (waking all waiting threads). It also explains why the waiting condition must be checked inside a while loop rather than an if statement to handle spurious wake‑ups and race conditions.

Implementation example:

public class Product {
    private String name;
    public Product(String name) { this.name = name; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}
public class Test {
    public static void main(String[] args) {
        Queue
queue = new ArrayDeque<>();
        for (int i = 0; i < 100; i++) {
            new Thread(new Producer(queue, 100)).start();
            new Thread(new Consumer(queue, 100)).start();
        }
    }
}
public class Producer implements Runnable {
    private Queue
queue;
    private int maxCapacity;
    public Producer(Queue queue, int maxCapacity) { this.queue = queue; this.maxCapacity = maxCapacity; }
    @Override
    public void run() {
        synchronized (queue) {
            while (queue.size() == maxCapacity) {
                try { wait(); } catch (InterruptedException e) { e.printStackTrace(); }
            }
            if (queue.size() == 0) { queue.notifyAll(); }
            queue.offer(new Product("Product" + new Random().nextInt()));
        }
    }
}
public class Consumer implements Runnable {
    private Queue
queue;
    private int maxCapacity;
    public Consumer(Queue queue, int maxCapacity) { this.queue = queue; this.maxCapacity = maxCapacity; }
    @Override
    public void run() {
        synchronized (queue) {
            while (queue.isEmpty()) {
                try { wait(); } catch (InterruptedException e) { e.printStackTrace(); }
            }
            if (queue.size() == maxCapacity) { queue.notifyAll(); }
            Product product = queue.poll();
        }
    }
}

The code demonstrates the three key steps for the producer: acquiring the lock, waiting while the queue is full, notifying consumers when the queue becomes non‑empty, and finally adding a product. The consumer follows the symmetric logic, waiting while the queue is empty and notifying producers when space becomes available.

In summary, the producer‑consumer model is frequently asked in interviews; it provides decoupling, asynchrony, and the ability to balance speed differences between threads, and its correct implementation relies on the proper use of wait() within a while loop and appropriate notify() / notifyAll() calls.

JavaConcurrencymultithreadingProducer Consumerwait-notify
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.