生产者/消费者模式要求在同一个进程地址空间内执行的两个线程。

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

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

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

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

java 生产者消费者模式 java生产者和消费者模式_java

优点:
(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();
    }
}