DEV Community

Dev Cookies
Dev Cookies

Posted on

๐Ÿ”„ Mastering `wait()` and `notify()` in Java: A Producer-Consumer Example

Multithreading is one of the most powerful concepts in Java โ€” and understanding inter-thread communication using wait() and notify() is essential for writing efficient concurrent programs.

In this blog, weโ€™ll walk you through:

โœ… What wait() and notify() do
โœ… How to use them properly with synchronized blocks
โœ… A real-world Producer-Consumer implementation
โœ… Full code + output explanation


๐Ÿ” What are wait() and notify()?

  • wait(): Causes the current thread to release the monitor and go into a waiting state until another thread calls notify() or notifyAll() on the same object.
  • notify(): Wakes up a single thread that is waiting on the object's monitor.

๐Ÿง  These methods must be called inside a synchronized block or method, otherwise a IllegalMonitorStateException is thrown.


๐Ÿงช Use Case: Producer-Consumer Problem

A producer thread generates data and puts it in a shared queue. A consumer thread removes and processes data from that queue.

Weโ€™ll use wait() and notify() to make sure:

  • Producer waits when the queue is full.
  • Consumer waits when the queue is empty.
  • They notify each other when they perform a task.

โœ… Full Java Code

๐Ÿ’ก ProducerConsumer.java

import java.util.LinkedList;
import java.util.Queue;

public class ProducerConsumer {

    private final Queue<Integer> queue = new LinkedList<>();
    private final int CAPACITY = 5;

    public synchronized void produce(int item) throws InterruptedException {
        while (queue.size() == CAPACITY) {
            System.out.println("Queue is full. Producer is waiting...");
            wait();  // wait until consumer consumes
        }

        queue.add(item);
        System.out.println("Produced: " + item);
        notify();  // notify a waiting consumer
    }

    public synchronized int consume() throws InterruptedException {
        while (queue.isEmpty()) {
            System.out.println("Queue is empty. Consumer is waiting...");
            wait();  // wait until producer produces
        }

        int item = queue.poll();
        System.out.println("Consumed: " + item);
        notify();  // notify a waiting producer
        return item;
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿ’ก Main.java

public class Main {

    public static void main(String[] args) {
        ProducerConsumer pc = new ProducerConsumer();

        // Producer Thread
        Thread producerThread = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    pc.produce(i);
                    Thread.sleep(500); // simulate time to produce
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        // Consumer Thread
        Thread consumerThread = new Thread(() -> {
            for (int i = 1; i <= 10; i++) {
                try {
                    pc.consume();
                    Thread.sleep(800); // simulate time to consume
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        });

        producerThread.start();
        consumerThread.start();
    }
}
Enter fullscreen mode Exit fullscreen mode

๐Ÿงพ Sample Output

Produced: 1
Consumed: 1
Produced: 2
Produced: 3
Consumed: 2
Consumed: 3
...
Queue is full. Producer is waiting...
Consumed: 5
Produced: 6
...
Queue is empty. Consumer is waiting...
Produced: 10
Consumed: 10
Enter fullscreen mode Exit fullscreen mode

โš ๏ธ Common Pitfalls

โŒ Mistake โœ… Solution
Calling wait() outside a synchronized block Always call inside synchronized methods or blocks
Using if instead of while for wait condition Use while to re-check condition after wakeup
Using notify() instead of notifyAll() when multiple threads wait Use notifyAll() if multiple consumers or producers may be waiting

๐Ÿ“š Summary

  • wait() and notify() are tools for coordinating threads sharing a common resource.
  • Always use them with a proper lock (like synchronized method or block).
  • A correct usage of while, wait, and notify can help you implement thread-safe coordination.

๐Ÿš€ Try This Yourself

  • Change the queue capacity to 1 or 2 and observe behavior.
  • Add multiple producer and consumer threads and use notifyAll() instead of notify().

Top comments (0)