设计模式之生产者与消费者的代码实现
本文主要讲述生产者和消费者模式,文中会使用通俗易懂的案例,使你更好地学习本章知识点并理解原理,做到有道无术。
什么是生产者和消费者模式
生产者消费者模式其实并不属于常见的23种设计模式之一,它是Controlnet网络中特有的一种传输数据模式,设置方便,使用安全快捷。生产者消费者模式,其实是一种通过容器解决生产者和消费者之间强耦合问题的设计模式。
生活中的生产者和消费者模式
在生活中,有很多店铺的经营方式跟生产者和消费者模式其实很相似,比如以下这些场景。
1.蛋糕店
在飘香四溢的蛋糕店中,我们能看到各式各样诱人的面包或者蛋糕,摆放在柜台中等待客户购买。江帅比较喜欢黑森林蛋糕和肠仔包,不知道大家喜欢哪些面包和蛋糕。
这些面包和蛋糕都是由糕点师在厨房中制造出来的,然后摆放在柜台中。因柜台的容量有限,且消费者的消费量也有限等原因,糕点师不会无限地再制作面包和蛋糕。当柜台摆满后,糕点师就不会再继续制作了;而当柜台已经空了或者即将要空了,糕点师就会继续制作。一般情况下,糕点师不会与购物的客户直接对接。这样的模式,其实就跟设计模式中的生产者和消费者类似。
2.水果店
我们知道,每个人平时都需要适当地进食一些水果,因为水果中含丰富的维生素和维他命,是咱们人体所需的。而喜欢吃水果的人也可以分为2类,一类是特别喜欢吃榴莲的,一类是受不了榴莲味不吃榴莲的,江帅则属于后者,你们是属于那种呢。
大部分人买水果都会去水果店或者超市,水果由果农生产出来,经过一系列途径进入到水果店或者超市中。当水果滞销时,店家会减少进货甚至不进货;而当水果热销短缺时,店家则会进货。生产水果的果农并不与购买水果的客户直接对接,这样的模式也会跟设计模式中的生产者和消费者类似。
生产者和消费者模式的代码实现
接下来江帅就以蛋糕店举例,通过生产者和消费者模式来实现,此案例会建立在多线程的基础上。首先我会创建一个产品类蛋糕类,和一个缓冲区蛋糕店类,代码如下所示:
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();
}
}
生成者把生成的数据存放到缓冲区里,当缓冲区不为空时需要通知消费者消费,当缓冲区满了则自己进入等待。
消费者者需要数据时则从缓冲区中获取,当缓冲区不为空时需要通知生产者生成,当缓冲区满了则自己进入等待。
在生产者与消费者模式中,生产者并不与消费者产生直接的联系。而是通过缓冲区把生产者(糕点师)和消费者(客户)进行关联,使生产者和消费者的耦合度降低,达到解耦性。
猜你喜欢LIKE
相关推荐HOT
更多>>servlet底层原理是什么?
1、ServletAPI核心类与接口2、Servlet类处理请求的流程创建servlet类的步骤:创建一个命名为TestServlet继承javax.servlet.http.HttpServlet类详情>>
2023-05-30 10:41:22多线程的优势与劣势分别是什么?
多线程是指在同一个程序中,同时运行多个线程,每个线程都可以独立执行不同的任务,相互之间不会干扰。多线程的优势和劣势如下:优势:提高程序...详情>>
2023-05-30 10:32:12设计模式之生产者与消费者的代码实现
本文主要讲述生产者和消费者模式,文中会使用通俗易懂的案例,使你更好地学习本章知识点并理解原理,做到有道无术。什么是生产者和消费者模式生...详情>>
2023-05-30 10:25:46从零开始学Java之interface接口
一.接口简介简介Java中的接口(interface)类似于是一种特殊的抽象类,它也是众多抽象方法的集合。接口的定义方式、组成部分都与抽象类相似,却比...详情>>
2023-05-29 11:26:17热门推荐
如何进行mysql数据备份?
沸什么是servlet的生命周期?servlet请求处理流程是怎样的?
热servlet底层原理是什么?
热怎样编写java程序?
新多线程的优势与劣势分别是什么?
ssm框架的作用与原理是什么?
设计模式之生产者与消费者的代码实现
接口和抽象类有什么区别?4个方面对比
从零开始学Java之interface接口
从零开始学Java之Java中的内部类是怎么回事?
一分钟带你了解MySQL——基础与介绍
在java中,super关键字怎样使用
什么是事件流以及事件流的传播机制 ?
弹性盒有哪些属性是在父元素身上?