In computing, the producer–consumer problem (also known as the
bounded-buffer problem) is a classic example of a multi-process
synchronization problem. The problem describes two processes, the
producer and the consumer, which share a common, fixed-size buffer used
as a queue.
- The producer’s job is to generate data, put it into the buffer, and start again.
- At the same time, the consumer is consuming the data (i.e. removing it from the buffer), one piece at a time.
Benefit of Producer Consumer Pattern
Its indeed a useful design pattern and used most commonly while writing multi-threaded or concurrent code. here is few of its benefit:
1)
Producer Consumer Pattern simple development. you can Code Producer and
Consumer independently and Concurrently, they just need to know shared
object.
2) Producer doesn't need to know about who is consumer or how many consumers are there. Same is true with Consumer.
3) Producer and Consumer can work with different speed. There is no risk of Consumer consuming half-baked item.
In fact by monitoring consumer speed one can introduce more consumer for better utilization.
4) Separating producer and Consumer functionality result in more clean, readable and manageable code.
Here is complete Java program to solve producer consumer problem in Java
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Java program to solve Producer Consumer problem using wait and
notify
* method in Java. Producer Consumer is also a popular concurrency design
pattern.
*/
public class
ProducerConsumerSolution {
public static void
main(String args[]) {
Vector sharedQueue = new Vector();
int size
= 4;
Thread prodThread = new Thread(new Producer(sharedQueue,
size), "Producer");
Thread consThread = new Thread(new Consumer(sharedQueue,
size), "Consumer");
prodThread.start();
consThread.start();
}
}
class Producer implements Runnable {
private final Vector sharedQueue;
private final int
SIZE;
public Producer(Vector sharedQueue, int size) {
this.sharedQueue = sharedQueue;
this.SIZE = size;
}
@Override
public void run() {
for (int i =
0; i < 7; i++) {
System.out.println("Produced: "
+ i);
try
{
produce(i);
} catch (InterruptedException
ex) {
Logger.getLogger(Producer.class.getName()).log(Level.SEVERE,
null, ex);
}
}
}
private void produce(int i) throws InterruptedException {
//wait if queue is
full
while (sharedQueue.size() == SIZE) {
synchronized
(sharedQueue)
{
System.out.println("Queue is full
" + Thread.currentThread().getName()
+ " is waiting , size: " + sharedQueue.size());
sharedQueue.wait();
}
}
//producing element
and notify consumers
synchronized
(sharedQueue)
{
sharedQueue.add(i);
sharedQueue.notifyAll();
}
}
}
class Consumer implements Runnable {
private final Vector sharedQueue;
private final int
SIZE;
public Consumer(Vector sharedQueue, int size) {
this.sharedQueue = sharedQueue;
this.SIZE = size;
}
@Override
public void run() {
while (true) {
try
{
System.out.println("Consumed: "
+ consume());
Thread.sleep(50);
} catch (InterruptedException
ex) {
Logger.getLogger(Consumer.class.getName()).log(Level.SEVERE,
null, ex);
}
}
}
private int consume()
throws InterruptedException {
//wait if queue is
empty
while (sharedQueue.isEmpty()) {
synchronized
(sharedQueue)
{
System.out.println("Queue is empty
" + Thread.currentThread().getName()
+ " is waiting ,
size: " + sharedQueue.size());
sharedQueue.wait();
}
}
//Otherwise consume
element and notify waiting producer
synchronized
(sharedQueue)
{
sharedQueue.notifyAll();
return
(Integer)
sharedQueue.remove(0);
}
}
}
I strongly recommend to run this program on your IDE to see the output.
No comments