Two threads manipulating a synchronized buffer. - Java Thread

Java examples for Thread:Producer Consumer

Description

Two threads manipulating a synchronized buffer.

Demo Code

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

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

class Consumer implements Runnable {
  private static final SecureRandom generator = new SecureRandom();
  private final Buffer sharedLocation; // reference to shared object

  public Consumer(Buffer sharedLocation) {
    this.sharedLocation = sharedLocation;
  }// w ww .  ja va2  s. com

  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");
  }
}

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 SynchronizedBuffer implements Buffer {
  private final Lock accessLock = new ReentrantLock();

  // conditions to control reading and writing
  private final Condition canWrite = accessLock.newCondition();
  private final Condition canRead = accessLock.newCondition();

  private int buffer = -1; // shared by producer and consumer threads
  private boolean occupied = false; // whether buffer is occupied

  public void blockingPut(int value) throws InterruptedException {
    accessLock.lock(); // lock this object

    // output thread information and buffer information, then wait
    try {
      // while buffer is not empty, place thread in waiting state
      while (occupied) {
        System.out.println("Producer tries to write.");
        displayState("Buffer full. Producer waits.");
        canWrite.await();// wait until buffer is empty
      }

      buffer = value; // set new buffer value

      // indicate producer cannot store another value
      // until consumer retrieves current buffer value
      occupied = true;

      displayState("Producer writes " + buffer);

      // signal any threads waiting to read from buffer
      canRead.signalAll();
    } finally {
      accessLock.unlock(); // unlock this object
    }
  }

  public int blockingGet() throws InterruptedException {
    int readValue = 0; // initialize value read from buffer
    accessLock.lock(); // lock this object

    // output thread information and buffer information, then wait
    try {
      // if there is no data to read, place thread in waiting state
      while (!occupied) {
        System.out.println("Consumer tries to read.");
        displayState("Buffer empty. Consumer waits.");
        canRead.await(); // wait until buffer is full
      }
      occupied = false;

      readValue = buffer; // retrieve value from buffer
      displayState("Consumer reads " + readValue);
      canWrite.signalAll();
    } finally {
      accessLock.unlock(); // unlock this object
    }

    return readValue;
  }
  private void displayState(String operation) {
    try {
      accessLock.lock(); // lock this object
      System.out.printf("%-40s%d\t\t%b%n%n", operation, buffer, occupied);
    } finally {
      accessLock.unlock(); // unlock this object
    }
  }
}

interface Buffer {
  public void blockingPut(int value) throws InterruptedException;

  public int blockingGet() throws InterruptedException;
}

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

    System.out.printf("%-40s%s\t\t%s%n%-40s%s%n%n", "Operation", "Buffer",
        "Occupied", "---------", "------\t\t--------");

    // execute the Producer and Consumer tasks
    executorService.execute(new Producer(sharedLocation));
    executorService.execute(new Consumer(sharedLocation));

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

Result


Related Tutorials