class BufferItem {
   public volatile double value = 0;          // multiple threads access
   public volatile boolean occupied = false;  // so make these `volatile'
   public volatile Thread thread = null;
}

class BoundedBuffer {  // designed for a single producer thread and
                       // a single consumer thread
   private int numSlots = 0;
   private BufferItem[] buffer = null;
   private int putIn = 0, takeOut = 0;

   public BoundedBuffer(int numSlots) {
      if (numSlots <= 0) throw new IllegalArgumentException("numSlots<=0");
      this.numSlots = numSlots;
      buffer = new BufferItem[numSlots];
      for (int i = 0; i < numSlots; i++) buffer[i] = new BufferItem();
   }

   public void deposit(double value) {
      if (buffer[putIn].occupied) {
         Thread producer = Thread.currentThread();
         buffer[putIn].thread = producer;
//                      producer.yield(); // force "bad" context switch
         producer.suspend();
         buffer[putIn].thread = null;
      }
      buffer[putIn].value = value;
      buffer[putIn].occupied = true;
      Thread consumer = buffer[putIn].thread;
      putIn = (putIn + 1) % numSlots;
      if (consumer != null) consumer.resume(); // a consumer is waiting
   }

   public double fetch() {
      double value;
      if (!buffer[takeOut].occupied) {
         Thread consumer = Thread.currentThread();
         buffer[takeOut].thread = consumer;
//                      consumer.yield(); // force "bad" context switch
         consumer.suspend();
         buffer[takeOut].thread = null;
      }
      value = buffer[takeOut].value;
      buffer[takeOut].occupied = false;
      Thread producer = buffer[takeOut].thread;
      takeOut = (takeOut + 1) % numSlots;
      if (producer != null) producer.resume(); // a producer is waiting
      return value;
   }
}

/* ............... Example compile and run(s)

D:\>javac srbb.java bbpc.java

D:\>java ProducerConsumer -s6 -p2 -c2 -R10
ProducerConsumer: numSlots=6, pNap=2, cNap=2, runTime=10
All threads started
age=60, PRODUCER napping for 643 ms
age=60, Consumer napping for 1851 ms
age=720, PRODUCER produced item 0.123381
PRODUCER deposited item 0.123381
age=720, PRODUCER napping for 663 ms
age=1380, PRODUCER produced item 0.396578
PRODUCER deposited item 0.396578
age=1380, PRODUCER napping for 1900 ms
age=1930, Consumer wants to consume
Consumer fetched item 0.123381
age=1930, Consumer napping for 140 ms
age=2090, Consumer wants to consume
Consumer fetched item 0.396578
age=2090, Consumer napping for 1623 ms
age=3300, PRODUCER produced item 0.660364
PRODUCER deposited item 0.660364
age=3300, PRODUCER napping for 1541 ms
age=3680, Consumer wants to consume
Consumer fetched item 0.660364
age=3680, Consumer napping for 1119 ms
age=4840, Consumer wants to consume
age=4840, PRODUCER produced item 0.886704
PRODUCER deposited item 0.886704
age=4840, PRODUCER napping for 1616 ms
Consumer fetched item 0.886704
age=4840, Consumer napping for 909 ms
age=5770, Consumer wants to consume
age=6430, PRODUCER produced item 0.318411
PRODUCER deposited item 0.318411
age=6430, PRODUCER napping for 1507 ms
Consumer fetched item 0.318411
age=6430, Consumer napping for 969 ms
age=7420, Consumer wants to consume
age=7970, PRODUCER produced item 0.552109
PRODUCER deposited item 0.552109
age=7970, PRODUCER napping for 812 ms
Consumer fetched item 0.552109
age=7970, Consumer napping for 817 ms
age=8790, PRODUCER produced item 0.0881424
PRODUCER deposited item 0.0881424
age=8790, PRODUCER napping for 119 ms
age=8790, Consumer wants to consume
Consumer fetched item 0.0881424
age=8790, Consumer napping for 649 ms
age=8900, PRODUCER produced item 0.502511
PRODUCER deposited item 0.502511
age=8900, PRODUCER napping for 712 ms
age=9450, Consumer wants to consume
Consumer fetched item 0.502511
age=9450, Consumer napping for 838 ms
age=9620, PRODUCER produced item 0.0185393
PRODUCER deposited item 0.0185393
age=9620, PRODUCER napping for 575 ms
age()=10060, time to stop the threads and exit
                                            ... end of example run(s)  */
