生产者与消费者的关系是什么?市场供需关系

发布时间 2023-06-08 20:02:59作者: 可爱的小锋

前言

本文主要讲述生产者和消费者模式,文中使用通俗易懂的案例,使你更好的学习本章知识点并理解原理,做到有道无术。

一.什么是生产者和消费者模式

生产者消费者模式并不属于常见的23种设计模式的,它是Controlnet网络中特有的一种传输数据的模式,设置方便,使用安全快捷。生产者消费者模式是一种通过容器解决生产者和消费者之间强耦合问题的设计模式。

二.生活中的生产者和消费者模式

在生活中很多店铺的经营方式之一跟生产者和消费者模式很相似

1.蛋糕店

在面包和蛋糕是由糕点师在厨房中制造出来的,然后摆放在柜台中的,因柜台上的容量是有限而且消费者的消费量也是有限的原因,糕点师不会无限地在制作面包和蛋糕,当柜台摆满后,糕点师不会再继续制作,当柜台要空了或者即将要空了,糕点师就会继续制作了,糕点师不与消费的客户直接对接。这样的模式就跟设计模式中的生产者和消费者类似。

image.png

2.水果店

大部分人买水果都会去水果店或者超市买水果,水果是由果农生产出来然后经过一系列销售然后进入到水果店或者超市中,而店家会根据店铺大小和周围的消费情况来决定水果的进货。当水果滞销的时候,店家则会减少甚至不进货,而当水果热销甚至短缺的时候,店家则会进货甚至提高进货量,生产水果的果农并不与购买水果的客户直接对接。这样的模式就跟设计模式中的生产者和消费者类似。

在这里插入图片描述

3.烧烤店

在烧烤店中,老板需要提前准备好食材,如果消费人员多,食材不够,老板则会多准备食材,如果消费人员少,老板则会少准备食材,出售食材的商贩并不与到烧烤店消费的客户直接对接。这样的模式就跟设计模式中的生产者和消费者类似。

image.png

三.生产者和消费者模式的实现

接下来我们以蛋糕店举例,通过生产者和消费者模式来实现,此案例建立在多线程的基础上。首先创建一个产品类蛋糕类和一个缓冲区蛋糕店类

package com.qianfeng.ran;
/*
 * @author:江帅
 *   	产品类
 *      	蛋糕类
 */
public class Cake {
    //蛋糕名
    private String name;

    public Cake() {
    }

    public Cake(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Cake{" +
                "name='" + name + '\'' +
                '}';
    }
}



/*
 * @author:江帅
 *   	缓冲区
 *          蛋糕店
 */
class CakeShop {
    //存放蛋糕的柜台   --  存放蛋糕类对象的数组
    private Cake[] counter = new Cake[10];
    //已有蛋糕的数量   --  指针
    private int index = 0;

    //厨师把蛋糕放在柜台的行为  --  生产者存放产品的方法
    public synchronized void input(Cake cake){
        //判断柜台是否满了  --  判断数组是否已满
        while(index == counter.length){
            try {
                //让糕点师暂停制作蛋糕 --  使生产者线程进入等待
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //把蛋糕放在柜台上  --  把产品存放在数组中
        counter[index++] = cake;
        System.out.println(Thread.currentThread().getName()+"大厨制作了一个"+cake.getName()+",柜台上有"+index+"个蛋糕");
        //通知客人可以继续消费    --  唤醒消费者继续消费
        this.notifyAll();
    }

    //客户购买蛋糕的行为     --  消费者消费产品的方法
    public synchronized void outPut(){
        //判断柜台是否为空
        while (index == 0){
            try {
                //客户停止消费    --  使消费者线程进入等待
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //客户购买的蛋糕
        Cake cake = counter[--index];
        System.out.println(Thread.currentThread().getName()+"购买了一个"+cake.getName());
        //已购买的蛋糕所在柜台的位置为null
        counter[index] = null;
        //提醒所有的糕点师该继续继续制作蛋糕      --  唤醒所有的生产者
        this.notifyAll();
    }
}

再创建生产者类消费者类并且都实现 Runnable 接口

package com.qianfeng.ran;

import java.util.Random;

/*
 * @author:江帅
 *      生产者
 *          糕点师
 */
public class PastryCook implements Runnable {
    //蛋糕店对象
    private CakeShop cakeShop;
    public PastryCook(CakeShop cakeShop){
        this.cakeShop = cakeShop;
    }

    @Override
    public void run() {
        while (true){
            //制作蛋糕	--	创建蛋糕类对象
            Cake cake = makeCake();
            //存放到柜台中
            cakeShop.input(cake);
            try {
                //适当休眠
                Thread.sleep(new Random().nextInt(2000)+1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }


	/**
     *  制作蛋糕            --  创建随机的蛋糕
     * @return  蛋糕类对象
     */
    private Cake makeCake() {
        String[] cakeNames = {"黑森林蛋糕","抹茶蛋糕","草莓蛋糕","水果蛋糕","青草蛋糕"};
        //随机生成蛋糕名
        String cakeName = cakeNames[(int)(Math.random()*cakeNames.length)];
        //创建蛋糕类对象并返回
        return new Cake(cakeName);
    }
}

/*
 * @author:江帅
 *      消费者
 *          人类
 */
class Human implements Runnable{
    //蛋糕店对象
    private CakeShop cakeShop;
    public Human(CakeShop cakeShop){
        this.cakeShop = cakeShop;
    }

    @Override
    public void run() {
        while(true){
            //客户购买蛋糕行为
            cakeShop.outPut();
            try {
                //适当休眠
                Thread.sleep(new Random().nextInt(3000)+2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

最后通过生产者和消费者模式来模拟用户消费和厨师生产的场景

package com.qianfeng.ran;

/*
 * @author:江帅
 *      客户端
 */
public class Demo {
    public static void main(String[] args) {
        //----------打印结果为糕点师生成蛋糕、消费者购买蛋糕的场景-------
        //---------------当蛋糕达到10个,糕点师不会继续生产------------
        //-----------------当蛋糕售空后,消费者不会再购买--------------
        //创建蛋糕店
        CakeShop cakeShop = new CakeShop();
        //创建多个糕点师并开始在蛋糕店制作蛋糕
        PastryCook pastryCook = new PastryCook(cakeShop);
        new Thread(pastryCook,"小当家").start();
        new Thread(pastryCook,"南翔").start();

        //创建多个消费者并开始在蛋糕店购买蛋糕
        Human human = new Human(cakeShop);
        new Thread(human,"江帅").start();
        new Thread(human,"Jack Ma").start();
        new Thread(human,"企鹅马").start();

    }
}

四.总结

生成者把生成的数据存放到缓冲区里,当缓冲区里不为空时需要通知消费者消费,当缓冲区满了则自己进入等待。

消费者者需要数据的时候则从缓冲区里获取,当缓冲区不为空时需要通知生产者生成,当缓冲区满了则自己进入等待。

在这个生产者与消费者模式中,生产者并不与消费者产生直接的联系。而是通过缓冲区(缓冲区)把生产者(糕点师)和消费者(客户)进行关联,使生产者和消费者的耦合度降低,达到解耦性。

下一章,我们将带大家学习钢铁侠的形成(设计模式之装饰者模式)。