Producer Consumer Design Pattern using wait() and notify()
Producer Consumer Problem is a classical concurrency problem. In fact it is one of the concurrency design pattern.
This article is continuation of my post Producer Consumer Design Pattern in which I have explained basic idea, real life example, uses and benefits of Producer Consumer Design Pattern.
Producer Consumer Design Patter can either be implemented using following two approaches.
In this post I will explain implementation using wait() and notify() method. If you are interested in the implementation using Blocking Queue, you can check my post Producer Consumer Design Pattern using BlockingQueue.
The Object class in java contains three final methods that allows threads to communicate about the lock status of a resource. These methods are wait(), notify() and notifyAll().
We can use wait() method to pause execution of thread.
notify() and notifyAll() methods are used to wake up waiting thread. Both notify() and notifyAll() method sends a notification but notify() sends the notification to only one of the waiting thread, no guarantee which thread will receive notification and notifyAll() sends the notification to all threads.
So if only one thread is waiting for an object lock, also known as a monitor then both notify and notifyAll will send the notification to it. If multiple threads are waiting on a monitor then notify will only inform one of the lucky thread and rest will not receive any notification, but notifyAll will inform all threads.
Understanding Java Program
In this program, we have two threads named PRODUCER and CONSUMER, which are instance of Producer and Consumer class respectively. Both of these class implements Runnable interface.
The logic of what producer and the consumer should do is written in their respective run() method.
Main thread starts both PRODUCER and CONSUMER threads and also create an object of LinkedList class i.e. sharedQ to share as Queue between them.
maximum size of sharedQ is defined using maxSize variable.
import java.util.LinkedList; import java.util.Queue; import java.util.Random; /** * Simple Java Program to test Producer Consumer Design Pattern * using wait, notify and notifyAll() methods * * */ public class ProducerConsumerTest { public static void main(String[] args) throws InterruptedException { final Queue sharedQ = new LinkedList < Integer >(); Thread consumerThread = new Thread(new Consumer(sharedQ, 4), "CONSUMER"); Thread producerThread = new Thread(new Producer(sharedQ, 4), "PRODUCER"); producerThread.start(); consumerThread.start(); } }
Producer runs in an infinite loop and keeps inserting random integer value from 1 to 100 into sharedQ until the queue is full.
We use condition while(queue.size == maxSize) to confirm if queue is full or not. This condition is a part of synchronized block on shareQ object, so that no other thread can modify the queue while executing this line of code.
If sharedQ is full then our PRODUCER thread waits until CONSUMER thread consumes one item and makes space in queue.
It calls notify() method to inform PRODUCER thread.
Both wait() and notify() methods are called on shared object which is sharedQ in our case.
/** * Producer Thread will keep producing values for Consumer. * * It will use wait() method when Queue is full and * use notify() method to send notification to Consumer Thread. * * */ class Producer implements Runnable { private final Queue sharedQ; private int maxSize; public Producer(Queue sharedQ, int maxSize) { this.sharedQ = sharedQ; this.maxSize = maxSize; } @Override public void run(){ while(true) { synchronized (sharedQ) { while(sharedQ.size()==maxSize) { try { System.out.println("Queue is full"); sharedQ.wait(); } catch(InterruptedException e) { e.printStackTrace(); } } Random random = new Random(); int number = random.nextInt(100); System.out.println("Producing value " + number); sharedQ.add(number); sharedQ.notify(); } } } }
Similarly Consumer runs in an infinite loop and keeps consuming integers from sharedQ until the queue is empty. It uses while(sharedQ.isEmpty()) condition to keep checking if sharedQ is empty or not.
/** * Consumer Thread will consumer values form shared queue. * * It will use wait() method to wait if queue is empty. * * It will also use notify method to send notification * to producer thread after consuming values from queue. * * */ class Consumer implements Runnable { private final Queue sharedQ; private int maxSize; public Consumer(Queue sharedQ, int maxSize) { this.sharedQ = sharedQ; this.maxSize = maxSize; } @Override public void run(){ while(true) { synchronized (sharedQ) { while(sharedQ.isEmpty()) { try { System.out.println("Que is Empty"); sharedQ.wait(); } catch(InterruptedException e) { e.printStackTrace(); } } int number = (int) sharedQ.poll(); System.out.println("removing Element " + number); sharedQ.notify(); } } } }
That's all for this topic. If you guys have any suggestions or queries, feel free to drop a comment. We would be happy to add that in our post. You can also contribute your articles by creating contributor account here.
Happy Learning 🙂
If you like the content on CodePumpkin and if you wish to do something for the community and the planet Earth, you can donate to our campaign for planting more trees at CodePumpkin Cauvery Calling Campaign.
We may not get time to plant a tree, but we can definitely donate ₹42 per Tree.
About the Author
Tags: Concurrency, Design Patterns, Java, Multithreading, notify, Producer Consumer Design Pattern, Synchronization, Thread, wait
Comments and Queries
If you want someone to read your code, please put the code inside <pre><code> and </code></pre> tags. For example:<pre><code class="java"> String foo = "bar"; </code></pre>For more information on supported HTML tags in disqus comment, click here.