天天看點

java生産者消費者模型(線程協作)

       生産者-消費者(producer-consumer)問題,也稱作有界緩沖區(bounded-buffer)問題,兩個程序共享一個公共的固定大小的緩沖區。其中一個是生産者,用于将消息放入緩沖區;另外一個是消費者,用于從緩沖區中取出消息。問題出現在當緩沖區已經滿了,而此時生産者還想向其中放入一個新的資料項的情形,其解決方法是讓生産者此時進行休眠,等待消費者從緩沖區中取走了一個或者多個資料後再去喚醒它。同樣地,當緩沖區已經空了,而消費者還想去取消息,此時也可以讓消費者進行休眠,等待生産者放入一個或者多個資料時再喚醒它。

     生産者消費者模型準确說應該是“生産者-消費者-倉儲”模型,離開了倉儲,生産者消費者模型就顯得沒有說服力了。對于此模型,應該明确一下幾點:

1、生産者僅僅在倉儲未滿時候生産,倉滿則停止生産。

2、消費者僅僅在倉儲有産品時候才能消費,倉空則等待。

3、當消費者發現倉儲沒産品可消費時候會通知生産者生産。

4、生産者在生産出可消費産品時候,應該通知等待的消費者去消費。

接下來我們以生産和消費水果為例來說明此問題:

/**
 * 水果類
 */
public class FruitInfo {
	private String name;
	private String color;
	private int weight;
	
	public FruitInfo(String name,String color){
		this.name=name;
		this.color=color;
	}
	public int getWeight() {
		return weight;
	}
	public void setWeight(int weight) {
		this.weight = weight;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
}
           

=============================

/*

* 共享類
 */
class CubbyHole {
	public final int SIZE=10;//倉庫容量
	private String[] nameArr={"蘋果","香蕉","葡萄","橘子","橙子","西瓜","桃子","李子","梨子","木瓜"};
	private String[] colorArr={"紅色","黃色","紫紅","黃色","金黃","暗綠","淺綠","淺紫色","淺綠色","淺藍"};
	// 倉庫或者叫做緩沖區
	private ArrayList<FruitInfo> proList=new ArrayList<FruitInfo>(); 
	/**
	 * 取資料的同步方法
	 * @param thName
	 * @return
	 */
	public synchronized void get(String thName) {
		while (proList.isEmpty()) {
			try {
				wait(); // 條件不符合,則wait,會釋放對象鎖
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		int i=proList.size()-1;
		FruitInfo fp=proList.get(i);
		proList.remove(i);
		notifyAll(); // 通知喚醒其他等待管程的線程
		System.out.println(thName + " 消費了倉庫中的第" +(i+1)+"個水果=="+fp.getName()+","+fp.getColor()+
				"   >倉庫剩餘"+proList.size()+"個水果");
	}

	/**
	 * 存放資料的同步方法
	 * @param thName
	 */
	public synchronized void put(String thName) {
		while (proList.size()==SIZE) {
			try {
				wait(); // 條件不符合,則wait,會釋放對象鎖
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		int i=new Random().nextInt(SIZE);
		FruitInfo fp=new FruitInfo(nameArr[i], colorArr[i]);
		proList.add(fp);
		notifyAll(); // 通知喚醒其他等待管程的線程
		System.out.println(thName + " 向倉庫中放進去了一個水果=="+fp.getName()+","+fp.getColor()+
				"    >倉庫剩餘"+proList.size()+"個水果");
	}
	/*
	 * 初始化倉庫中的水果
	 */
	void init(int num){
		FruitInfo fp=null;
		for(int i=0;i<num;i++){
			 fp=new FruitInfo(nameArr[i], colorArr[i]);
			 proList.add(fp);
		}
		System.out.println("倉庫中初始庫存水果個數為"+num);
	}
}
           

================================================

class Producer extends Thread { // 生産者線程類
	private CubbyHole cubbyhole;

	public Producer(CubbyHole c) {
		cubbyhole = c;
	}

	public void run() { // 定義run()方法
		for (int i = 0; i < 20; i++) { // 共産生20個
			cubbyhole.put(this.getName());
			try {
				Thread.sleep((long)(Math.random()*2000));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
} 
           

=================================

class Consumer extends Thread { // 消費者線程類
	private CubbyHole cubbyhole;

	public Consumer(CubbyHole c) {
		cubbyhole = c;
	}

	public void run() { // 定義run()方法

		for (int i = 0; i <10; i++) {// 消費10個
			cubbyhole.get(this.getName());
			try {
				Thread.sleep((long)(Math.random()*500));
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
} 
           

===============================

public class ProducerConsumerTest { // 主類:測試
	public static void main(String[] args) {
		CubbyHole c = new CubbyHole();// the shared data object
		int num=new Random().nextInt(c.SIZE);
		c.init(num);
		Producer p1 = new Producer(c); // Producer線程
		p1.setName("producer1");
		Consumer c1 = new Consumer(c); // Consumer線程
		c1.setName("consumer1");
		Consumer c2 = new Consumer(c); // 另一個Consumer線程
		c2.setName("consumer2");

		c1.start(); // 啟動消費者1線程
		p1.start(); // 啟動生産者線程
		c2.start(); // 啟動消費者2線程
	}
}
           

========================================

運作效果如下所示:

倉庫中初始庫存水果個數為3
producer1 向倉庫中放進去了一個水果==香蕉,黃色    >倉庫剩餘4個水果
consumer1 消費了倉庫中的第4個水果==香蕉,黃色   >倉庫剩餘3個水果
consumer2 消費了倉庫中的第3個水果==葡萄,紫紅   >倉庫剩餘2個水果
consumer2 消費了倉庫中的第2個水果==香蕉,黃色   >倉庫剩餘1個水果
consumer2 消費了倉庫中的第1個水果==蘋果,紅色   >倉庫剩餘0個水果
producer1 向倉庫中放進去了一個水果==蘋果,紅色    >倉庫剩餘1個水果
consumer1 消費了倉庫中的第1個水果==蘋果,紅色   >倉庫剩餘0個水果
producer1 向倉庫中放進去了一個水果==蘋果,紅色    >倉庫剩餘1個水果
consumer1 消費了倉庫中的第1個水果==蘋果,紅色   >倉庫剩餘0個水果
producer1 向倉庫中放進去了一個水果==李子,淺紫色    >倉庫剩餘1個水果
consumer1 消費了倉庫中的第1個水果==李子,淺紫色   >倉庫剩餘0個水果
producer1 向倉庫中放進去了一個水果==李子,淺紫色    >倉庫剩餘1個水果
consumer1 消費了倉庫中的第1個水果==李子,淺紫色   >倉庫剩餘0個水果
producer1 向倉庫中放進去了一個水果==香蕉,黃色    >倉庫剩餘1個水果
consumer1 消費了倉庫中的第1個水果==香蕉,黃色   >倉庫剩餘0個水果
producer1 向倉庫中放進去了一個水果==桃子,淺綠    >倉庫剩餘1個水果
consumer1 消費了倉庫中的第1個水果==桃子,淺綠   >倉庫剩餘0個水果
.........
           

可以看出,多個線程協同工作,按照規則生産和消費水果!

繼續閱讀