您的位置:首页 > 编程语言 > Java开发

生产者/消费者模式 (java)

2016-03-31 20:38 591 查看
生产者/消费者模式要求在同一个进程地址空间内执行的两个线程。

生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。

消费者线程从缓冲区中获得物品,然后释放缓冲区。

当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。

当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。



优点:

(1)解耦。假设生产者和消费者分别是两个类。如果让生产者直接调用消费者的某个方法,那么生产者对于消费者就会产生依赖(也就是耦合)。将来如果消费者的代码发生变化,可能会影响到生产者。而如果两者都依赖于某个缓冲区,两者之间不直接依赖,耦合也就相应降低了。

(2)支持并发。生产者直接调用消费者的某个方法,还有另一个弊端。由于函数调用是同步的(或者叫阻塞的),在消费者的方法没有返回之前,生产者只好一直等在那边。万一消费者处理数据很慢,生产者就会浪费时间。

(3)支持忙闲不均。缓冲区还有另一个好处。如果制造数据的速度时快时慢,缓冲区的好处就体现出来了。当数据制造快的时候,消费者来不及处理,未处理的数据可以暂时存在缓冲区中。等生产者的制造速度慢下来,消费者再慢慢处理掉。

public class ProducerConsumer {
public static void main(String[] args) {
// TODO 自动生成方法存根
Box box = new Box();
Producer p = new Producer(box);
Consumer c = new Consumer(box);
p.start();
c.start();
}
}


public class Consumer extends Thread {
private Box box;
private String name;
public Consumer(Box b) {
box = b;
}
public void run() {
int value = 0;
while (true) {
int realNum = Box.getRealNum();
if (realNum > 0) {
value = box.get();
System.out.println("取出的元素是:" + value);
}
try {
sleep((int) (Math.random() * 5000));
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}// while
}// run
}


public class Producer extends Thread {
private Box box;
private String name;
private static int maxCap = 5;// 最大的缓冲区大小
public Producer(Box b) {
box = b;
}
public void run() {
while (true) {
int realNum = Box.getRealNum();
if (realNum < maxCap) {
int random = (int) (Math.random() * 10);
box.put(random);
System.out.println("插入的元素是: " + random);
}
try {
sleep((int) (Math.random() * 5000));
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}// while
}// run
}


public class Box {
private static int maxCap = 5;// 最大的缓冲区大小
private static int realNum = 0;// 缓冲区中实际元素的数目
private int[] arr = new int[5];// 声明一个数组作为缓冲区
private int getValue;// get()返回的数字值
/**
* 返回缓冲区中现有元素个数
*
* @return
*/
public static synchronized int getRealNum() {
return realNum;
}
/**
* 获取缓冲区的一个元素
*
* @return
*/
public synchronized int get() {
if (realNum < maxCap) {// 缓冲区未满,唤醒生产者插入元素
notifyAll();
}
while (realNum == 0) {// 缓冲区中没有元素
try {
// 等待生产者写入数据
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}// while
if (realNum > 0) {// 缓冲区不为空
System.out.println("取出前缓冲区有" + realNum + "个元素");
getValue = arr[--realNum];
System.out.println("取出后缓冲区有" + realNum + "个元素");
}
// 遍历输出缓存区所有元素
System.out.print("取出后缓冲区剩下元素: ");
for (int i = 0; i < realNum; i++) {
System.out.print(arr[i] + "、");
}
System.out.println();
return getValue;
}// get

/**
* 向缓冲区插入一个元素
*
* @param value
*/
public synchronized void put(int value) {

if (realNum < maxCap) {// 缓冲区未满,唤醒生产者插入元素
notifyAll();
}
while (realNum == maxCap) {
try {
// 缓冲区满,等待消费者取走元素
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
if (realNum < maxCap) {
System.out.println("插入前缓冲区有" + realNum + "个元素");
arr[realNum++] = value;
System.out.println("插入后缓冲区有" + realNum + "个元素");
}
// 遍历输出缓存区所有元素
System.out.print("插入后缓冲区有元素: ");
for (int i = 0; i < realNum; i++) {
System.out.print(arr[i] + "、");
}
System.out.println();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息