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 BlockingQueueimplementations provided by Java like LinkedBlockingQueue, PriorityBlockingQueue, ArrayBlockingQueue and SynchronousQueue which are all thread safe.
Read Also : What is Thread Synchronization in Java
IntroductionProducer 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 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.
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.
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.
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).