Producer Consumer Solution using BlockingQueue in Java Thread


Producer Consumer is the most common problem of Java concurrency and multi-threading. It arises during the synchronization that helps to manage multiple threads trying to access a shared resource. This article will help us to find Producer Consumer Solution using BlockingQueue in Java Thread.

Producer Consumer Problem and BlockingQueue

Understanding Producer Consumer Problem

Producer and Consumer are two distinct entities or processes that use a shared queue. This queue is of a fixed size buffer. The producer generates pieces of information and stores them in the queue. The consumer consumes the given information and removes them from the queue.

The actual problem occurs

  • When the producer keeps generating data even though the buffer is full.

  • When the consumer tries to remove data even the buffer is empty.

  • Either the producer or consumer’s speed is slow.

  • Both are trying to update the buffer at the same time.

The solution

  • When the buffer is full, the producer must stop the data generation.

  • When the buffer is empty, the consumer must stop removing the information from the buffer.

  • Producer and Consumer work only when neither the buffer is empty nor it is full.

BlockingQueue

Java provides the BlockingQueue interface in ‘java.util.concurrent’ package. The main advantage of using this queue is that while retrieving and deleting an item, it waits for the queue to become non-empty. Also, while adding an item, it waits for available space. This feature makes it the perfect choice for the Producer Consumer Solution.

Syntax

BlockingQueue< Type > nameOfObject = new LinkedBlockingQueue<>();

Here, LinkedBlockingQueue is a class that implements BlockingQueue interface.

Producer Consumer Solution using BlockingQueue in Java

Approach

  • Create two classes and their corresponding constructors. Both classes will extend the ‘Thread’ class. The first class is for Producer and the Second one for Consumer.

  • In both classes, define BlockingQueue of type ‘Integer’ and pass them as a parameter to constructors. Here, ‘Integer’ is a wrapper class.

  • In Producer class, we override the in-built method ‘run()’ to produce the data from Producer end. Now, take for loop that will iterate 5 times and by using the ‘put()’ method, it will store data into BlockingQueue with an interval of 1 second.

  • In Consumer class, again override the in-built method ‘run()’ to consume the data from Consumer end using built-in method named ‘take()’.

  • In the main() method, define an object of BlockingQueue and pass them to the constructor of both producer and consumer class as arguments

Example

import java.util.concurrent.*;
class Producr extends Thread {
   protected BlockingQueue<Integer> blcque;
   Producr(BlockingQueue<Integer> blcque) { // constructor
      this.blcque = blcque;
   }
   public void run() { // overriding run method
      while (true) {
         for(int i = 1; i <= 5; i++) {
            try {
               System.out.println("Producer is running " + i);
               blcque.put(i); // to produce data
               // produce data with an interval of 1 sec
               Thread.sleep(1000);
            }
           // to handle exception
           catch (InterruptedException exp) {
              System.out.println("An interruption occurred at Producer");
            }
         }
      }
   }
}
class Consumr extends Thread {
   protected BlockingQueue<Integer> blcque;
   Consumr(BlockingQueue<Integer> blcque) { // constructor
      this.blcque = blcque;
   }
   public void run() { // overriding run method
      try {
         while (true) {
            Integer elem = blcque.take(); // to consume data
            System.out.println("Consumer is running " + elem);
         }
      }
      // to handle exception
      catch (InterruptedException exp) {
         System.out.println("An interruption occurred at Producer");
      }
   }
}
public class Solution {
   public static void main(String[] args) throws InterruptedException {
      // create an object of BlockingQueue
      BlockingQueue<Integer> bufrShr = new LinkedBlockingQueue<>();
      
      // passing object of BlockingQueue as arguments
      Producr threadProd = new Producr(bufrShr);
      Consumr threadCon = new Consumr(bufrShr);
      
      // to start the process
      threadProd.start();
      threadCon.start();
      
      // to exit the process after 5 sec
      Thread.sleep(5000);
      System.exit(0);
   }
}

Output

Producer is running 1
Consumer is running 1
Producer is running 2
Consumer is running 2
Producer is running 3
Consumer is running 3
Producer is running 4
Consumer is running 4
Producer is running 5
Consumer is running 5

Conclusion

We started this article by defining the Producer Consumer Problem and in the next section, we proposed a possible solution for this problem by introducing the BlockingQueue interface. In the end, we discussed a Java program that showed us how we can use BlockingQueue to solve the given problem practically.

Updated on: 20-Jul-2023

521 Views

Kickstart Your Career

Get certified by completing the course

Get Started
Advertisements