class ProducerConsumer{
    public static void main(String[] args){
	Queue q = new Queue(10);
	Thread p1 = new Producer("p1",q);
	Thread p2 = new Producer("p2",q);
	Thread c1 = new Consumer("c1",q);
	Thread c2 = new Consumer("c2",q);
	p1.start();p2.start();
	c1.start();c2.start();
    }
}
	
class Queue {
    private int [] que;
    private int nextIn,nextOut,filled,queSize;
    
    public Queue(int size){
	que = new int[size];
	filled = 0;
	nextIn = 1;
	nextOut = 1;
	queSize = size;
    }

    public synchronized void deposit(int item)
    {
	while (filled == queSize){
	    try {
		wait();
	    } 
	    catch (InterruptedException e){};
	}
	que[nextIn] = item;
	nextIn = (nextIn + 1) % queSize;
	filled++;
	notify();
    }

    public synchronized int fetch()
    {
	int item;
	while (filled==0){
	    try {
		wait();
	    } 
	    catch (InterruptedException e){};
	}
	item = que[nextOut];
	nextOut = (nextOut+1) % queSize;
	filled--;
	notify();
	return item;
    }
}

class Producer extends Thread {
    private Queue buffer;
    String id;
    public Producer(String id,Queue que){
	buffer = que;
	this.id = id;
    }

    public void run(){
	int new_item = 0;
	while (true){
	    new_item++;
	    System.out.println(id+"   "+new_item);
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException e){}
	    buffer.deposit(new_item);
	}
    }
}

class Consumer extends Thread {
    private Queue buffer;
    String id;
    public Consumer(String id, Queue que){
	buffer = que;
	this.id = id;
    }
    
    public void run(){
	int stored_item;
	while (true){
	    stored_item = buffer.fetch();
	    try {
		Thread.sleep(100);
	    } catch (InterruptedException e){}
	    System.out.println(id+"    "+stored_item);
	} 
    }
}
	
    
