練習:生產者-消費者

關於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();
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章