1. 程式人生 > >java多執行緒之消費者生產者模式

java多執行緒之消費者生產者模式

/*@author shijin
* 生產者與消費者模型中,要保證以下幾點:
* 1 同一時間內只能有一個生產者生產		生產方法加鎖sychronized
* 2 同一時間內只能有一個消費者消費		消費方法加鎖sychronized
* 3 生產者生產的同時消費者不能消費		生產方法加鎖sychronized
* 4 消費者消費的同時生產者不能生產		消費方法加鎖sychronized
* 5 共享空間空時消費者不能繼續消費		消費前迴圈判斷是否為空,空的話將該執行緒wait,釋放鎖允許其他同步方法執行
* 6 共享空間滿時生產者不能繼續生產		生產前迴圈判斷是否為滿,滿的話將該執行緒wait,釋放鎖允許其他同步方法執行   
*/

//主類
class  ProducerConsumer
{
	public static void main(String[] args) 
	{
		StackBasket s = new StackBasket();
		Producer p = new Producer(s);
		Consumer c = new Consumer(s);
		Thread tp = new Thread(p);
		Thread tc = new Thread(c);
		tp.start();
		tc.start();
	}
}

//
class Mantou
{
	private int id;
	
	Mantou(int id){
		this.id = id;
	}

	public String toString(){
		return "Mantou :" + id;
	}
}

//共享棧空間
class StackBasket
{
	Mantou sm[] = new Mantou[6];
	int index = 0;
	
	/** 
	* show 生產方法.
	* show 該方法為同步方法,持有方法鎖;
	* show 首先迴圈判斷滿否,滿的話使該執行緒等待,釋放同步方法鎖,允許消費;
	* show 當不滿時首先喚醒正在等待的消費方法,但是也只能讓其進入就緒狀態,
	* show 等生產結束釋放同步方法鎖後消費才能持有該鎖進行消費
	* @param m 元素
	* @return 沒有返回值 
	*/ 

	public synchronized void push(Mantou m){
		try{
			while(index == sm.length){
				System.out.println("!!!!!!!!!生產滿了!!!!!!!!!");
				this.wait();
			}
			this.notify();
		}catch(InterruptedException e){
			e.printStackTrace();
		}catch(IllegalMonitorStateException e){
			e.printStackTrace();
		}
		
		sm[index] = m;
		index++;
		System.out.println("生產了:" + m + " 共" + index + "個饅頭");
	}

	/** 
	* show 消費方法
	* show 該方法為同步方法,持有方法鎖
	* show 首先迴圈判斷空否,空的話使該執行緒等待,釋放同步方法鎖,允許生產;
	* show 當不空時首先喚醒正在等待的生產方法,但是也只能讓其進入就緒狀態
	* show 等消費結束釋放同步方法鎖後生產才能持有該鎖進行生產
	* @param b true 表示顯示,false 表示隱藏 
	* @return 沒有返回值 
	*/ 
	public synchronized Mantou pop(){
		try{
			while(index == 0){
				System.out.println("!!!!!!!!!消費光了!!!!!!!!!");
				this.wait();
			}
			this.notify();
		}catch(InterruptedException e){
			e.printStackTrace();
		}catch(IllegalMonitorStateException e){
			e.printStackTrace();
		}
		index--;
		System.out.println("消費了:---------" + sm[index] + " 共" + index + "個饅頭");
		return sm[index];
	}
}

class Producer implements Runnable
{
	StackBasket ss = new StackBasket();
	Producer(StackBasket ss){
		this.ss = ss;
	}

	/** 
	* show 生產程序. 
	*/ 
	public void run(){
		for(int i = 0;i < 20;i++){
			Mantou m = new Mantou(i);
			ss.push(m);
//			System.out.println("生產了:" + m + " 共" + ss.index + "個饅頭");
//			在上面一行進行測試是不妥的,對index的訪問應該在原子操作裡,因為可能在push之後此輸出之前又消費了,會產生輸出混亂
			try{
				Thread.sleep((int)(Math.random()*500));
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}
}

class Consumer implements Runnable
{
	StackBasket ss = new StackBasket();
	Consumer(StackBasket ss){
		this.ss = ss;
	}

	/** 
	* show 消費程序.
	*/ 
	public void run(){
		for(int i = 0;i < 20;i++){
			Mantou m = ss.pop();
//			System.out.println("消費了:---------" + m + " 共" + ss.index + "個饅頭");
//	同上	在上面一行進行測試也是不妥的,對index的訪問應該在原子操作裡,因為可能在pop之後此輸出之前又生產了,會產生輸出混亂
			try{
				Thread.sleep((int)(Math.random()*1000));
			}catch(InterruptedException e){
				e.printStackTrace();
			}
		}
	}
}