Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 4

1

Producer Consumer Problem In Java Using BlockingQueue

Producer Consumer design pattern is an example of concurrency pattern in Java. The


solution of the producer consumer problem can be classic wait and notify thread operations
that are commonly used in multi-threading but in this article, we will deal with this by using
the BlockingQueue implementation which was introduced in Java 5.

The BlockingQueue interface can be found inside the java.util.concurrent package.


There are many BlockingQueue implementations provided by Java like
LinkedBlockingQueue, PriorityBlockingQueue, ArrayBlockingQueue and SynchronousQueue
which are all thread safe.

Read Also :  What is Thread Synchronization in Java

Introduction
Producer Consumer design pattern has two threads namely: the Producer and the
Consumer. These threads are linked by a common buffer which is basically a queue.
Both the threads are independent in their nature of work. The producer will generate the
data, put it in the queue and keep on repeating the same process. The consumer will keep
on consuming or using the data by removing it from the queue.

Producer Consumer Problem:


The main problem to understand here is if the queue or buffer is full, the producer should not
try to put any more data on it. Similarly, if the queue is empty then the consumer should not
try to extract or remove data from the empty queue.

Solution:
The BlockingQueue interface provides two methods put() and take() which are used
implicitly in blocking the Producer and the Consumer thread respectively. The thread
(Consumer) trying to remove item from an empty queue waits or is blocked until the
Producer thread adds an item to the queue. Similarly, the thread (Producer) trying to add an
item to a full queue is blocked until any Consumer thread makes some space in the queue
by removing the item(s) from the queue.

Producer Consumer Solution using BlockingQueue Example:


Producer Class

The code snippet given below represents a typical Producer class generating some data and
2

putting it in the BlockingQueue. If the buffer is full, it will wait for the Consumer thread to
remove some data from the queue before resuming its operation again. We are trying to
generate some Integer value as the data here in this example.

package com.javahungry;
import java.util.concurrent.BlockingQueue;

class Producer implements Runnable {

private final BlockingQueue<Integer> blockingQueue;

public Producer(BlockingQueue<Integer> blockingQueue) {


this.blockingQueue = blockingQueue;
}

public void run() {


for (int i = 10; i <= 100; i += 10) {
try {
System.out.println("Data produced : " + i);
blockingQueue.put(i);
} catch (InterruptedException ex) {
System.out.println("Producer thread interrupted.");
}
}
}
}

Consumer Class

The code snippet given below represents a Consumer class that removes the data from
queue and does some processing on it. If the buffer is empty, it will wait until the Producer
thread generates and puts some data into the queue.

package com.javahungry;
import java.util.concurrent.BlockingQueue;

class Consumer implements Runnable {

private final BlockingQueue<Integer> blockingQueue;


3

public Consumer(BlockingQueue<Integer> blockingQueue) {


this.blockingQueue = blockingQueue;
}

public void run() {


while (true) {
try {
System.out.println("Data consumed : " + blockingQueue.take());
} catch (InterruptedException ex) {
System.out.println("Consumer thread interrupted.");
}
}
}
}

Testing the Solution using main class:


We will now test the solution that we have created using BlockingQueue. As you can see
below, we have created a shared BlockingQueue in which the Producer thread will put the
data and the same data will be consumed by the Consumer thread. Here, we have used
LinkedBlockingQueue class to implement the BlockingQueue interface. Further, we create
the Producer and the Consumer thread, start them and observe the result.

package com.javahungry;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class ProducerConsumerExample {

public static void main(String[] args) {

// Common buffer created using LinkedBlockingQueue


BlockingQueue<Integer> blockingQueue =  
new LinkedBlockingQueue<Integer>();

// Producer thread creation


Thread producer = new Thread(new Producer(blockingQueue));
4

// Consumer thread creation


Thread consumer = new Thread(new Consumer(blockingQueue));

// Start Producer and Consumer thread


producer.start();
consumer.start();

Output:
Data produced : 10
Data produced : 20
Data consumed : 10
Data produced : 30
Data consumed : 20
Data produced : 40
Data consumed : 30
Data produced : 50
Data consumed : 40
Data consumed : 50
Data produced : 60
Data produced : 70
Data consumed : 60
Data produced : 80
Data consumed : 70
Data produced : 90
Data produced : 100
Data consumed : 80
Data consumed : 90
Data consumed : 100

It is evident from the above output that the data is getting generated and consumed
smoothly in a First-In, First-Out order as it is the feature of LinkedBlockingQueue. The
Producer thread is creating the data, putting it in the queue and Consumer thread is
removing it from the data implicitly without any need to write and notify statements. This
wraps up this article on Producer Consumer Problem in Java using multithreading
(BlockingQueue).

You might also like