`
mwei
  • 浏览: 121934 次
  • 性别: Icon_minigender_1
  • 来自: 抽象空间
社区版块
存档分类
最新评论

练习:生产者-消费者

    博客分类:
  • java
阅读更多
关于Object.wait()和Object.notify()/notifyAll()的使用,再写个练习。
生产者-消费者问题:有一个公共的资源池Source,生产者生产物品放到资源池中,消费者从资源池拿物品消费掉。
当资源池没有资源(物品)的时候,通知生产者生产物品放到资源池里;
当任何一个生产者生产完成之后,通知消费者们来消费物品;
消费者们会把所有资源消费掉,然后通知生产者生产物品;
啰嗦这么多,就是生产的时候只能有一个生产者,不能两个(多个)生产者连续生产;消费的时候可以有多个消费者连续消费。
就用这样的需求练习练习吧。
假设资源池Source是个长度为30的数组int[] source=new int[30]; //值[1,2,3...,28,29,30] 数组的值=相应下标+1;
数组的值只是用于标记,标记这个位置已经放置物品了;
第一次生产了20个物品,那么放置的位置是数组的下标[0,19],相应值是[1,20];
那么下次(可能是别的生产者)放置物品的开始位置(下标)是20;
通知消费者们来消费,那么消费者消费的开始位置(下标)是0;
消费完之后,如果第二次也生产了20个物品,那么放置的位置是数组的下标[20,9],相应值是[21,22..29,30,1,2...9,10];
那么下次(可能是别的生产者)放置物品的开始位置(下标)是10;通知消费者们来消费,那么消费者消费的开始位置(下标)是20;
此时把资源池想象成为一个可旋转的大圆桌,在圆桌的边缘放置了30个碟子,编号就是0到29;
通过向固定的方向旋转圆桌来有秩序的生产和消费^..^
还请JE上的朋友给点建议。
资源池类:
/**
 * 资源池
 * @author mwei
 * @version 1.0
 */
public class Source {
	public static final int CAPACITY=30;
	public static int[] source=new int[CAPACITY]; //值[1,2,3...,28,29,30]
	public static int in=0; //the position to set source
	public static int out=0; //the position to get source	
	public static final byte[] LOCK=new byte[0];
}

生产者类:
import java.util.Random;

public class Producer implements Runnable{
	public static Random random=new Random();
	public static volatile boolean prun=true; //信号量
	private String name;
	public Producer(String name){this.name=name;}
	public String getName(){return name;}
	public void run(){produce();}
	public void produce(){		
		while (true) {
			synchronized (Source.LOCK) {
				if (prun) {
					Source.LOCK.notifyAll();
					int planNum = random.nextInt(10) + 15; // 计划生产资源的数量,最少15个,最多24个
					int actualNum = 0;
					for (int i = Source.out; i < Source.CAPACITY + Source.out; i++) { // 查找放置资源的位置
						int index = i % Source.CAPACITY;
						if (Source.source[index] == 0) {
							Source.in = index; // 找到
							break;
						}
					}
					for (int i = 0; i < planNum; i++) { // 放置资源
						if (Source.source[Source.in] == 0) {
							actualNum++; // 统计实际放置资源的个数
							Source.source[Source.in] = Source.in + 1;
							Source.in = (++Source.in % Source.CAPACITY);
						}
					}
					int total = 0;
					for (int i = 0; i < Source.CAPACITY; i++) { // 统计资源池中总共的资源个数
						if (Source.source[i] != 0)
							total++;
					}
					System.out.print(this.getName() + "Plan : " + planNum
							+ "\t Produce : " + actualNum); // 输出计划量和实际生产量
					System.out.println("\tTotal : " + total + "\tRange : ["
							+ Source.out + ","
							+ (Source.in + Source.CAPACITY - 1)
							% Source.CAPACITY + "]"); // 资源总值及范围
					prun = false; // 生产者只生产一次
					Consumer.crun = true;
				} else {
					try {
						System.out.println(this.getName() + ".wait();");
						Source.LOCK.wait();
					} catch (InterruptedException ie) {
						ie.printStackTrace();
					}
				}
			} // end syn
		} // end while
	}
}

消费者类
public class Consumer implements Runnable{
	public static final int CONSUME_NUM=4;
	public static volatile boolean crun=false; //信号量
	private String name;
	public Consumer(String name){
		this.name=name;
	}
	public String getName(){
		return name;
	}
	public void run(){
		consume();
	}
	public void consume(){
		while (true) {
			synchronized (Source.LOCK) {
				if (crun) {
					Source.LOCK.notifyAll();
					int actualNum = 0;
					for (int i = 0; i < CONSUME_NUM; i++) {
						if (Source.source[Source.out] != 0) {
							actualNum++;
							Source.source[Source.out] = 0; // 消耗掉
							Source.out = (Source.out + 1) % Source.CAPACITY;
						} else {
							; // do nothing
						}
					}
					System.out.println(this.getName() + " : consumes "
							+ actualNum);
					int total = 0;
					for (int i = 0; i < Source.CAPACITY; i++) { // 统计资源池中总共的资源个数
						if (Source.source[i] != 0)
							total++;
					}
					if (total == 0) { // 消费者把资源消费光了再通知生产者
						crun = false;
						Producer.prun = true;
					}
				} else {
					try {
						System.out.println(this.getName() + ".wait();");
						Source.LOCK.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
			} // end syn
		} // end while
	}
}

测试:
/**
 * test 3 producers and 4 consumers
 * @author mwei
 */
public class Test {	
	public static void main(String[] args) {
		new Thread(new Producer("P1=>")).start();
		new Thread(new Producer("P2=>")).start();
		new Thread(new Producer("P3=>")).start();
		new Thread(new Consumer("C1=>")).start();
		new Thread(new Consumer("C2=>")).start();
		new Thread(new Consumer("C3=>")).start();
		new Thread(new Consumer("C4=>")).start();		

	}
}

运行结果的一部分:
P3=>Plan : 18	 Produce : 18	Total : 18	Range : [28,15]
C2=> : consumes 4
C3=> : consumes 4
C1=> : consumes 4
C4=> : consumes 4
P3=>.wait();
C2=> : consumes 2
P2=>Plan : 19	 Produce : 19	Total : 19	Range : [16,4]
C3=> : consumes 4
C1=> : consumes 4
C4=> : consumes 4
C2=> : consumes 4
P2=>.wait();
C3=> : consumes 3
C1=>.wait();
C4=>.wait();
C2=>.wait();
C3=>.wait();
P3=>Plan : 18	 Produce : 18	Total : 18	Range : [5,22]
P1=>.wait();
P2=>.wait();
C3=> : consumes 4
C1=> : consumes 4
P3=>.wait();
C4=> : consumes 4
C2=> : consumes 4
C3=> : consumes 2
C1=>.wait();
C4=>.wait();
C2=>.wait();
C3=>.wait();
P2=>Plan : 18	 Produce : 18	Total : 18	Range : [23,10]
P1=>.wait();
P3=>.wait();
P2=>.wait();
C1=> : consumes 4
C4=> : consumes 4
C3=> : consumes 4
C2=> : consumes 4
C1=> : consumes 2
C4=>.wait();
C3=>.wait();
C2=>.wait();



分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics