/**
 * ÎÄ¼þÃû£ºEx24.java
 * ÏîÄ¿-°ü£ºJAVA±à³ÌË¼Ïë - µÚ¶þÊ®Ò»ÕÂ²¢·¢
 * ×÷Õß£ºÕÅÎÄµÏ
 * ´´½¨ÈÕÆÚ£º2014-11-7
 */
package µÚ¶þÊ®Ò»ÕÂ²¢·¢;

import java.util.LinkedList;
import java.util.Queue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * @author ÕÅÎÄµÏ
 * ÀàÃû£ºEx24
 * ÀàËµÃ÷£ºÓÃµ½ÁË ·ºÐÍ£¬¶ÓÁÐ..... ¾«ËèÁË ~~~
 */
class FlowQueue<T> 
{
	private Queue<T> queue = new LinkedList<T>();
	private int maxSize;
	public FlowQueue(int maxSize) { this.maxSize = maxSize; }
	public synchronized void put(T v) throws InterruptedException 
	{
		while(queue.size() >= maxSize)
			wait();
		queue.offer(v);  //½«Ö¸¶¨µÄÔªËØ²åÈë´Ë¶ÓÁÐ
		maxSize++;
		notifyAll();
	}
	public synchronized T get() throws InterruptedException 
	{
		while(queue.isEmpty())
			wait();
		T returnVal = queue.poll(); //»ñÈ¡²¢ÒÆ³ý´Ë¶ÓÁÐµÄÍ·£¬Èç¹û´Ë¶ÓÁÐÎª¿Õ
		maxSize--;
		notifyAll();
		return returnVal;
	}
}
class Item 
{
	private static int counter;
	private int id = counter++;
	public String toString() { return "Item " + id; }
}// Produces Item objects
	
class Producer implements Runnable 
{
	private int delay;
	private FlowQueue<Item> output;
	public Producer(FlowQueue<Item> output, int sleepTime) 
	{
		this.output = output;
		delay = sleepTime;
	}
	public void run() 
	{
		for(;;) {
			try {
				output.put(new Item());
				TimeUnit.MILLISECONDS.sleep(delay);
			} catch(InterruptedException e) { return; }
		}
	}
}// Consumes any object
	
class Consumer implements Runnable 
{
	private int delay;
	private FlowQueue<?> input;
	public Consumer(FlowQueue<?> input, int sleepTime) 
	{
		this.input = input;
		delay = sleepTime;
	}
	public void run()
	{
		for(;;) 
		{
			try 
			{
				System.out.println(input.get());
				TimeUnit.MILLISECONDS.sleep(delay);
			} catch(InterruptedException e) { return; }
		}
	}
}
public class Ex24 
{
	public static void main(String[] args) throws Exception 
	{
		if(args.length < 2) {
			System.err.println("Usage java E24_ProducerConsumer" +
			" <producer sleep time> <consumer sleep time>");
			System.exit(1);
		}
		int producerSleep = Integer.parseInt(args[0]);
		int consumerSleep = Integer.parseInt(args[1]);
		
		
		FlowQueue<Item> fq = new FlowQueue<Item>(100);
		ExecutorService exec = Executors.newFixedThreadPool(2);
		exec.execute(new Producer(fq, producerSleep));
		exec.execute(new Consumer(fq, consumerSleep));
		TimeUnit.SECONDS.sleep(2);
		exec.shutdownNow();
	}
}
