Java:如何使用消费者生产者模式来进行并发控制?

概论

举个例子:有一个固定容量的货架,生产者放商品进来,消费者拿商品出去,为了保证正常放入和正常拿出(数据的正确性,不会出现超过容量的存放,拿到空气)。使用同步块中的 wait 和 notifAll 方法进行控制。

形如

synchronized (被锁的对象) {
     被锁的对象.wait();            //线程进入阻塞状态,把锁住的资源打开。  
     被锁的对象.notifyAll();      //通知其它所有的线程取消阻塞状态。
}        

商品

//商品
class Love{
    static String love="love";
    public String toString(){
        //所有商品都是love!
        return love;
    }
}

货架

//货架
class Shelves{
    List  goods;//商品
    int  VOLUME=10;//容量

    public Shelves(List goods) {
        this.goods = goods;
    }
}

生产者

//生产者
class Producer implements Runnable{
    Shelves shelves;//货架
    int count;//商品的数量

    //使用的货架
    public Producer(Shelves shelves) {
        this.shelves = shelves;
    }

    //生产商品到放到货架
    public void run() {
        //一直在生产
        while (true) {
            //获取货架上的商品个数
            count=shelves.goods.size();

            synchronized (shelves) {
                if (count > shelves.VOLUME) {
                    System.out.println("货架放不下了,暂停制作");
                    try {
                        //货架资源放出去
                        shelves.wait();
                    } catch (InterruptedException e) { e.printStackTrace(); }
                }else {
                    System.out.println("【生产者】:现在这里有"+count+"个商品");
                    System.out.println("努力制作了1个商品");
                    System.out.println("---------------------");
                    //生产一个商品
                    shelves.goods.add(new Love());
                    //有商品了,告知wait的消费者可以来消费了
                    shelves.notifyAll();
                    try {
                        //每0.5秒做一个
                        Thread.sleep(500);
                    } catch (Exception e) { e.printStackTrace();}
                }
            }
        }
    }
}

消费者

//消费者
class Consumer implements Runnable{
    Shelves shelves;//货架
    int count;//商品的数量
    public Consumer(Shelves shelves){
        this.shelves=shelves;
    }
    //消费者从货架取走商品
    public void run() {
        //每过2秒取走最后一个
        while (true) {
            count=shelves.goods.size();
            synchronized (shelves) {
                if (count == 0) {
                    System.out.println("【消费者】:货架没有商品了,等等吧,等他做出来在买。");
                    try {
                        shelves.wait();
                    } catch (InterruptedException e) { e.printStackTrace(); }
                } else {
                    //买到一个
                    System.out.println("【消费者】:买到1个商品,看看里面什么!----->"+(shelves.goods.get(count-1)).toString());
                    shelves.goods.remove(--count);
                    System.out.println("【消费者】:现在这里还有"+shelves.goods.size()+"个商品");
                    System.out.println("---------------------");
                    //通知制作
                    shelves.notifyAll();
                    try {
                        //每两秒消费一个商品
                        Thread.sleep(2000);
                    } catch (Exception e) { e.printStackTrace();}
                }
            }
        }
    }
}

测试:

public class LeaningThread {
    public static void main(String[] args) {
        //初始化货架,0个商品
        List<Love> list = new ArrayList<>();
        Shelves sl = new Shelves(list);
        //开启生产者线程
        new Thread(new Producer(sl)).start();
        //开启消费者线程
        new Thread(new Consumer(sl)).start();
    }
}

运行结果(手动结束程序运行):

 

注意

wait和notifyAll:必须在synchronized方法或块中使用,通过被锁的对象进行调用。

posted @ 2022-11-12 20:59  在博客做笔记的路人甲  阅读(45)  评论(0编辑  收藏  举报