问题描述

  • 生产者消费者问题(Producer-consumer problem),也称有限缓冲问题(Bounded-buffer problem),是一个多线程同步问题的经典案例。生产者生成一定量的数据放到缓冲区中,然后重复此过程;与此同时,消费者也在缓冲区消耗这些数据。生产者和消费者之间必须保持同步,要保证生产者不会在缓冲区满时放入数据,消费者也不会在缓冲区空时消耗数据。不够完善的解决方法容易出现死锁的情况,此时进程都在等待唤醒。

解决问题的核心

   保证同一资源被多个线程并发访问时的完整性。常用的同步方法是采用信号或加锁机制,保证资源在任意时刻至多被一个线程访问。


代码实现

利用Synchronized,wait() / notify()方法实现


import java.util.LinkedList;

/**
 * @Author GJ1e
 * @Create 2019/12/7
 * @Time 19:09
 * 
 * 缓冲区
 */
public class Storage {
    private final  int STORAGE_MAX = 10;

    //缓冲区载体
    private LinkedList<Object> list = new LinkedList<Object>();

    public void proudce(){

        synchronized(list){
            while (list.size()+1 > 10){
                System.out.println("生产者"+Thread.currentThread().getName()+"仓库已满");
                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.add(new Object());
            System.out.println("生产者"+Thread.currentThread().getName()
                    +"生产一个商品,现在库存为"+list.size());
            list.notifyAll();
        }
    }

    public void consume(){

        synchronized(this.list){

            while (list.size()==0){
                System.out.println("消费者"+Thread.currentThread().getName()+"仓库已空");

                try {
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            list.remove();
            System.out.println("消费者"+Thread.currentThread().getName()
                    +"已消费1个产品,现库存为"+list.size());
            list.notifyAll();
        }
    }
}


生产者


/**
 * @Author GJ1e
 * @Create 2019/12/7
 * @Time 19:26
 */
public class Producer implements Runnable {
    private  Storage storage;

    public Producer() {
    }

    public Producer(Storage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(1000);
                storage.proudce();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }
}


消费者


/**
 * @Author GJ1e
 * @Create 2019/12/7
 * @Time 19:31
 */
public class Consumer implements Runnable {

    private Storage storage;

    public Consumer(Storage storage) {
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                Thread.sleep(3000);
                storage.consume();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


主函数


/**
 * @Author GJ1e
 * @Create 2019/12/7
 * @Time 19:34
 */
public class TestPS {
    public static void main(String[] args) {
        Storage storage = new Storage();

        //生产者
        Thread p1 = new Thread(new Producer(storage));
        Thread p2 = new Thread(new Producer(storage));
        Thread p3 = new Thread(new Producer(storage));

        //消费者
        Thread c1 = new Thread(new Consumer(storage));
        Thread c2 = new Thread(new Consumer(storage));
        Thread c3 = new Thread(new Consumer(storage));

        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
        c3.start();
    }
}


输出结果

生产者Thread-2生产一个商品,现在库存为1
生产者Thread-0生产一个商品,现在库存为2
生产者Thread-1生产一个商品,现在库存为3
生产者Thread-1生产一个商品,现在库存为4
生产者Thread-0生产一个商品,现在库存为5
生产者Thread-2生产一个商品,现在库存为6
消费者Thread-4已消费1个产品,现库存为5
消费者Thread-3已消费1个产品,现库存为4
消费者Thread-5已消费1个产品,现库存为3
生产者Thread-0生产一个商品,现在库存为4
生产者Thread-1生产一个商品,现在库存为5
生产者Thread-2生产一个商品,现在库存为6
生产者Thread-2生产一个商品,现在库存为7
生产者Thread-0生产一个商品,现在库存为8
生产者Thread-1生产一个商品,现在库存为9
生产者Thread-2生产一个商品,现在库存为10
生产者Thread-0仓库已满
生产者Thread-1仓库已满
消费者Thread-4已消费1个产品,现库存为9
生产者Thread-1生产一个商品,现在库存为10
生产者Thread-0仓库已满
消费者Thread-3已消费1个产品,现库存为9
消费者Thread-5已消费1个产品,现库存为8
生产者Thread-0生产一个商品,现在库存为9
生产者Thread-2生产一个商品,现在库存为10
生产者Thread-0仓库已满
生产者Thread-1仓库已满
生产者Thread-2仓库已满
····


一个生产者线程运行produce方法,睡眠1s;一个消费者运行一次consume方法,睡眠3s。此次实验过程中,有3个生产者和3个消费者,也就是我们说的多对多的情况。仓库的容量为10,可以看出消费的速度明显慢于生产的速度,符合设定。