练习:生产者-消费者

关于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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值