Skip to main content

Implementing the Producer Consumer Pattern Using Wait and Notify in Java

Below are the conditions for producer consumer pattern. We need to ensure that the thread should not be blocked either if the buffer is empty or full. This is achieved by calling wait() and notify() method on the lock object which is used to synchronized the block of code. Please note that it is important for both threads to synchronize on the same monitor / lock object.
  • A producer produces values inside a buffer.
  • A consumer consumes the values from this buffer.
  • The buffer can be empty or full.
  • Producer and consumer runs in their own thread.

Note: wait() and notify() should not be called outside the synchronized code block

Below is the example code :

package com.refermynotes;

public class ProducerConsumerExample {
public static int[] buffer;
public static Object lock = new Object();
public static int count;

static class Producer{
public void produce(){
synchronized (lock) {
if(isFull(buffer)){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Produced: "+count);
buffer[count++] = 1;
lock.notifyAll();
}
}
}

static class Consumer{
public void consume(){
synchronized(lock){
if(isEmpty()){
try {
lock.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
buffer[--count] = 0;
System.out.println("Consumed: "+count);
lock.notifyAll();
}
}
}

private static boolean isEmpty() {
return count == 0;
}
private static boolean isFull(int[] buffer) {
return count == buffer.length;
}

public static void main(String[] args) {
buffer = new int[50];
count = 0;
final Producer p = new Producer();
final Consumer c = new Consumer();

Runnable producerTask = new Runnable() {
@Override
public void run() {
for(int i =0; i<100 font="" i="">
p.produce();
}
System.out.println("Done Producing");
}
};

Runnable consumerTask = new Runnable() {
@Override
public void run() {
for(int i =0; i<100 font="" i="">
c.consume();
}
System.out.println("Done Consuming");
}
};

Thread producerThread = new Thread(producerTask);
Thread consumerThread = new Thread(consumerTask);

producerThread.start();
consumerThread.start();

try {
producerThread.join();
consumerThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}

System.out.println("Remaining :"+count);

}
}

Comments

Popular posts from this blog

Knapsack Problem and Solution using Dynamic Programming

The knapsack problem or rucksack problem is a problem in combinatorial optimization: Given a set of items, each with a weight and a value, determine the number of each item to include in a collection so that the total weight is less than or equal to a given limit and the total value is as large as possible Given a knapsack of capacity m and number of items n of weight w1, w2, w3 ... , wn with profits p1, p2, p3..., pn. Let x1,x2,...,xn is an array that represents the items has been selected or not. If the item i is selected, then xi = 1 If the item i is not selected then x i = 0 In 0/1 knapsack, the item can be selected or completely rejected. The items are not allowed to be broken into smaller parts. The main objective is to place the items into the knapsack so that maximum profit is obtained or find the most valuable subset of items that fits into the knapsack. Constraints: The weight of the items chosen should not exceed the capacity of knapsack. Obj...

Important points on Classes and Methods in Java as per Java Language Specification

Class Declarations: A class declaration specifies a new named reference type. There are two kinds of class declarations: normal class declarations and enum declarations. It is a compile-time error if a class has the same simple name as any of its enclosing classes or interfaces. Class Modifiers: A class declaration may include class modifiers. The access modifier public pertains only to top level classes and member classes, not to local classes or anonymous classes. The access modifiers protected and private pertain only to member classes within a directly enclosing class declaration. The modifier static pertains only to member classes, not to top level or local or anonymous classes. It is a compile-time error if the same keyword appears more than once as a modifier for a class declaration. abstract Classes: An abstract class is a class that is incomplete, or to be considered incomplete. It is a compile-time error if an attempt is made to create an instance o...

Optimal Binary Search using Dynamic Programming

An optimal binary search tree is a binary search tree for which the nodes are arranged on levels such that the tree cost is minimum. If the probabilities of searching for elements of a set are known from accumulated data from past searches, then Binary Search Tree (BST) should be such that the average number of comparisons in a search should be minimum. eg. Lets the elements to be searched are A, B, C, D and probabilities of searching these items are 0.1, 0.2, 0.4 and 0.3 respectively. Lets consider 2 out of 14 possible BST containing these keys. Figure 1 Figure 2 Average number of comparison is calculated as sum of level*probability(key element) for each element of the tree. Lets the level of tree start from 1. Therefore, for figure 1 -     Average number of comparison = 1*0.1 +2*0.2 +3*0.4 +4*0.3  = 2.9                                  ...