/*   Producers-Consumers with a 2-positions buffer */
/*   Multithreads implementation                   */
 
/*   File Producers_Consumers_2B_simple.java       */
 
/*   ******************************************    */
/*                  Main program                   */
/*   ******************************************    */
 
public class Producers_Consumers_2B_simple {
  public static void main(String[] args) {
    Buffer2 b = new Buffer2();
    new Producer(b,1).start();
    new Producer(b,2).start();
    new Producer(b,3).start();
    new Consumer(b,1).start();
    new Consumer(b,2).start();
  }
}

/*   ******************************************    */
/*                    Producer                     */
/*   ******************************************    */

class Producer extends Thread {
  private Buffer2 buff;
  private int id;
  public Producer(Buffer2 b, int n) { buff = b; id = n; }
  public void run() {
    try {
      while (!isInterrupted()) {
        sleep((long)(java.lang.Math.random()*1000)); 
        buff.put(id); System.out.println("Producer " + id + " puts a datum");
      }
    } catch (InterruptedException e) { return; }
  }
}

/*   ******************************************    */
/*                    Consumer                     */
/*   ******************************************    */

class Consumer extends Thread {
  private Buffer2 buff;
  private int id;
  public Consumer(Buffer2 b, int n) { buff = b; id = n; }
  public void run() {
    try {
      while (!isInterrupted()) {
        sleep((long)(java.lang.Math.random()*1000)); 
        int k = buff.get();
        System.out.println("consumer " + id + " has retrieved the datum put by producer " + k);
      }
    } catch (InterruptedException e) { return; }
  }
}

/*   ******************************************    */
/*                      Buffer                     */
/*   ******************************************    */

class Buffer2 {
  private int content1, content2;
  private boolean is_empty1, is_empty2;
  public Buffer2() { is_empty1 = is_empty2 = true; }
  public synchronized void put(int k) throws InterruptedException {    
    while (!is_empty1) wait();
    if (is_empty2) { // buffer empty
      content2 = k;
      is_empty2 = false;
      notifyAll(); 
    }
    else {
      content1 = k;
      is_empty1  = false;
    }
  }
  public synchronized int get() throws InterruptedException {
    while (is_empty2) wait();
    int k = content2;
    if (!is_empty1) { // buffer full
      content2 = content1;
      is_empty1 = true;
      notifyAll(); 
    }
    else { is_empty2 = true; }
    return k;
  }
}


/*   ******************************************    */
  
