Producer and Consumer threads correctly manipulating a circular buffer. - Java Thread

Java examples for Thread:Producer Consumer

Description

Producer and Consumer threads correctly manipulating a circular buffer.

Demo Code

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.security.SecureRandom;

class CircularBuffer implements Buffer
{
   private final int[] buffer = {-1, -1, -1}; // shared buffer

   private int occupiedCells = 0; // count number of buffers used
   private int writeIndex = 0; // index of next element to write to
   private int readIndex = 0; // index of next element to read
   /*w ww.java 2 s.  co m*/
   public synchronized void blockingPut(int value)
      throws InterruptedException
   {
      while (occupiedCells == buffer.length) 
      {
         System.out.printf("Buffer is full. Producer waits.%n");
         wait(); // wait until a buffer cell is free
      } 

      buffer[writeIndex] = value; // set new buffer value
      writeIndex = (writeIndex + 1) % buffer.length;

      ++occupiedCells; // one more buffer cell is full
      displayState("Producer writes " + value);
      notifyAll(); // notify threads waiting to read from buffer
   } 
   public synchronized int blockingGet() throws InterruptedException
   {
      while (occupiedCells == 0) 
      {
         System.out.printf("Buffer is empty. Consumer waits.%n");
         wait(); // wait until a buffer cell is filled
      } 

      int readValue = buffer[readIndex]; // read value from buffer

      // update circular read index
      readIndex = (readIndex + 1) % buffer.length;

      --occupiedCells; // one fewer buffer cells are occupied
      displayState("Consumer reads " + readValue);
      notifyAll(); // notify threads waiting to write to buffer

      return readValue;
   }
    
   public synchronized void displayState(String operation)
   {
      System.out.printf("%s%s%d)%n%s", operation, 
         " (buffer cells occupied: ", occupiedCells, "buffer cells:  ");

      for (int value : buffer)
         System.out.printf(" %2d  ", value); // output values in buffer

      System.out.printf("%n               ");

      for (int i = 0; i < buffer.length; i++)
         System.out.print("---- ");

      System.out.printf("%n               ");

      for (int i = 0; i < buffer.length; i++)
      {
         if (i == writeIndex && i == readIndex)
            System.out.print(" WR"); // both write and read index
         else if (i == writeIndex)
            System.out.print(" W   "); // just write index
         else if (i == readIndex)
            System.out.print("  R  "); // just read index
         else
            System.out.print("     "); // neither index
      } 

      System.out.printf("%n%n");
   } 
}
interface Buffer
{
   public void blockingPut(int value) throws InterruptedException; 
   public int blockingGet() throws InterruptedException; 
}
class Producer implements Runnable
{
   private static final SecureRandom generator = new SecureRandom();
   private final Buffer sharedLocation; // reference to shared object

   public Producer(Buffer sharedLocation)
   {
      this.sharedLocation = sharedLocation;
   } 

   // store values from 1 to 10 in sharedLocation
   public void run()                             
   {
      int sum = 0;

      for (int count = 1; count <= 10; count++)
      {
         try // sleep 0 to 3 seconds, then place value in Buffer
         {
            Thread.sleep(generator.nextInt(3000)); // random sleep
            sharedLocation.blockingPut(count); // set value in buffer
            sum += count; // increment sum of values
         } 
         catch (InterruptedException exception) 
         {
            Thread.currentThread().interrupt(); 
         } 
      } 

      System.out.printf(
         "Producer done producing%nTerminating Producer%n");
   } 
}
class Consumer implements Runnable
{ 
   private static final SecureRandom generator = new SecureRandom();
   private final Buffer sharedLocation; // reference to shared object

   // constructor
   public Consumer(Buffer sharedLocation)
   {
      this.sharedLocation = sharedLocation;
   }

   // read sharedLocation's value 10 times and sum the values
   public void run()                                           
   {
      int sum = 0;

      for (int count = 1; count <= 10; count++) 
      {
         // sleep 0 to 3 seconds, read value from buffer and add to sum
         try 
         {
            Thread.sleep(generator.nextInt(3000));
            sum += sharedLocation.blockingGet();
         } 
         catch (InterruptedException exception) 
         {
            Thread.currentThread().interrupt(); 
         } 
      } 

      System.out.printf("%n%s %d%n%s%n", 
         "Consumer read values totaling", sum, "Terminating Consumer");
   } 
}

public class Main
{
   public static void main(String[] args) throws InterruptedException
   {
      ExecutorService executorService = Executors.newCachedThreadPool();

      CircularBuffer sharedLocation = new CircularBuffer();

      sharedLocation.displayState("Initial State");

      executorService.execute(new Producer(sharedLocation));
      executorService.execute(new Consumer(sharedLocation));

      executorService.shutdown();
      executorService.awaitTermination(1, TimeUnit.MINUTES); 
   }
}

Result


Related Tutorials