生产者-消费者模型

news2024/11/17 8:34:01

目录

1、生产者-消费者模型是什么

2、Java中的实现

3、应用于消息队列

3.1 引入依赖

3.2 rabbitmq网站新建队列queue

3.3 模块中配置application.yml

3.4 生产者实现类

3.5 单元测试,发送msg到rabbitmq的队列(my_simple_queue)

3.6 消费者实现类

3.7 从rabbitmq队列(my_simple_queue)消费数据

3.8 队列的配置类

小结


本文是RabbitMQ初入门-CSDN博客的进一步拓展,着重介绍该模型在消息队列(如rabbitmq)中的应用。

1、生产者-消费者模型是什么

首先,生产者-消费者模型是一种常见的并发编程模型,用于解决多线程或多进程环境下的数据共享与同步问题。在这个模型中,生产者负责生成数据,并将数据放入一个共享的缓冲区中,而消费者则从缓冲区中取出数据进行处理。

图片来源:Java多线程之生产者消费者模式详解_java_脚本之家

生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
这个阻塞队列就是用来给生产者和消费者解耦的。纵观大多数设计模式,都会找一个第三者出来进行解耦,如工厂模式的第三者是工厂类,模板模式的第三者是模板类。在学习一些设计模式的过程中,如果先找到这个模式的第三者,能帮助我们快速熟悉一个设计模式。(引自链接:Java多线程之生产者和消费者模型 - 简书)

生产者-消费者模型通常包含以下几个关键元素:

  1. 生产者:负责生成数据并放入缓冲区。生产者不断地生成数据,直到达到某个条件才停止。一般情况下,生产者在向缓冲区放入数据之前需要先检查缓冲区是否已满,如果已满则等待。

  2. 消费者:负责从缓冲区中取出数据并进行处理。消费者不断地从缓冲区中取出数据,直到达到某个条件才停止。一般情况下,消费者在从缓冲区取出数据之前需要先检查缓冲区是否为空,如果为空则等待。

  3. 缓冲区:作为生产者和消费者之间的共享数据结构,用于存储生产者生成的数据。缓冲区的大小限制了生产者和消费者之间的数据传输量,它可以是一个队列、堆栈、循环缓冲区等。

  4. 同步机制:用于保护缓冲区的访问,避免生产者和消费者同时对缓冲区进行读写操作而导致的数据不一致性。常见的同步机制包括互斥锁(mutex)、条件变量(condition variable)、信号量(semaphore)等。

生产者-消费者模型的核心思想是通过合理地协调生产者和消费者的工作,实现数据的有序生成和处理。通过使用适当的同步机制,可以保证生产者和消费者之间的互斥访问和协调,避免数据竞争和死锁等并发问题。

在Java中,生产者-消费者模型通常是通过多线程来实现的。生产者线程负责生成数据,将数据放入共享的缓冲区中;消费者线程则从缓冲区中取出数据进行处理。为了保证生产者和消费者之间的同步和互斥,可以使用Java提供的同步机制,例如synchronized关键字、ReentrantLock类、Condition接口等

2、Java中的实现

首先,可以把每个生产者和消费者各看成是一个线程,做如下定义:

生产者

public class ProduceThread extends  Thread{
    private IKFC kfc;
    public ProduceThread(String name,IKFC kfc) {
        super(name);
        this.kfc = kfc;
    }

    @Override
    public void run() {
       while(true){
           try {
               kfc.produce(getName());
               sleep(200);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }
}

消费者

public class ConsumerThread extends  Thread{
    private IKFC kfc;
    public ConsumerThread(String name, IKFC kfc) {
        this.kfc = kfc;
    }

    @Override
    public void run() {
       while(true){
           try {
               kfc.consume(getName());
               sleep(300);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
       }
    }
}

然后,可以通过synchronized方法, wait(), notifyAll()实现

这种方法等于使用this自带的锁来进行同步,具体办法是将入队和出队设成syncrhronized。生产者会在入队时(得到锁之后)检查队列是否为满,如果满了,就释放掉锁并进入阻塞(wait())。等到队列有了新的空位,消费者通过notifyAll()唤醒所有线程,此时被唤醒的生产者再次检查队列,发现了新的位置,就可以再继续将产品入队了,入队完后,生产者会用notifyAll()通知消费者去消费。相对的,消费者也会在出队时等待直至队列不为空,出队完通知。(引自链接:java生产消费者模式 java实现生产者消费者模型_mob6454cc6c8549的技术博客_51CTO博客)

实现类代码:

public class KFCImpl implements IKFC {

    private Queue<Food> queue = new LinkedBlockingQueue<>();
    private final int MAX_SIZE = 10;

    @Override
    public synchronized void produce(String name) throws InterruptedException {
        if (queue.size() >= MAX_SIZE) {
            System.out.println("[生产者" + name + "] KFC生成达到上限,停止生成......");
            wait();
        } else {
            Food food = new Food("上校鸡块");
            queue.add(food);
            System.out.println("[生产者" + name + "] 生成一个:" + food.getName() + ",KFC有食物:" + queue.size() + "个");

            //唤醒等待的线程来消费
            notifyAll();
        }
    }

    @Override
    public synchronized void consume(String name) throws InterruptedException {
        if (queue.isEmpty()) {
            System.out.println("[消费者" + name + "] KFC食物已空,消费者停止消费......");
            wait();
        } else {
            Food food = queue.poll();
            System.out.println("[消费者" + name + "] 消费一个:" + food.getName() + ",KFC有食物:" + queue.size() + "个");

            //唤醒等待的线程来消费
            notifyAll();
        }
    }
}

运行测试

public class Main {
    public static void main(String[] args) {
        IKFC kfc = new KFCImpl();

        Thread p1= new ProduceThread("A",kfc);
        Thread p2= new ProduceThread("B",kfc);
        Thread p3= new ProduceThread("C",kfc);

        Thread c1 = new ConsumerThread("X",kfc);
        Thread c2 = new ConsumerThread("Y",kfc);
        Thread c3 = new ConsumerThread("T",kfc);
        Thread c4 = new ConsumerThread("Z",kfc);
        Thread c5 = new ConsumerThread("K",kfc);

        p1.start();
        p2.start();
        p3.start();
        c1.start();
        c2.start();
        c3.start();
        c4.start();
        c5.start();

    }
}

测试结果,生产和消费交替进行

[生产者A] 生成一个:上校鸡块,KFC有食物:1个
[生产者B] 生成一个:上校鸡块,KFC有食物:2个
[生产者C] 生成一个:上校鸡块,KFC有食物:3个
[消费者Thread-2] 消费一个:上校鸡块,KFC有食物:2个
[生产者B] 生成一个:上校鸡块,KFC有食物:3个
[生产者C] 生成一个:上校鸡块,KFC有食物:4个
[生产者A] 生成一个:上校鸡块,KFC有食物:5个
[消费者Thread-3] 消费一个:上校鸡块,KFC有食物:4个
[消费者Thread-4] 消费一个:上校鸡块,KFC有食物:3个
[消费者Thread-1] 消费一个:上校鸡块,KFC有食物:2个
[消费者Thread-0] 消费一个:上校鸡块,KFC有食物:1个
[消费者Thread-2] 消费一个:上校鸡块,KFC有食物:0个
[生产者B] 生成一个:上校鸡块,KFC有食物:1个

3、应用于消息队列

在消息队列中,生产者-消费者模型也被广泛应用。消息队列是一种高效的消息传递机制,它可以实现不同应用程序或服务之间的异步通信。在消息队列中,生产者向队列中发送消息,而消费者则从队列中接收消息并进行处理。消息队列通常具有以下特点:

  1. 可靠性:消息队列通常使用持久化策略,可以保证消息在发送和接收过程中的可靠性和安全性。

  2. 异步性:生产者和消费者可以独立运行,不需要等待对方的响应,从而提高系统的吞吐量和响应速度。

  3. 解耦性:消息队列可以实现不同模块之间的解耦,降低应用程序的复杂度和耦合度。

  4. 扩展性:消息队列可以根据需求动态扩展,支持多个生产者和消费者并发访问。

在消息队列中,生产者-消费者模型可以通过使用不同的消息队列实现。常见的消息队列包括ActiveMQ、RabbitMQ、Kafka等,它们提供了丰富的API和特性,可以满足不同场景下的需求。例如,ActiveMQ支持JMS规范,提供了消息确认、持久化、事务等特性;RabbitMQ支持AMQP协议,具有高可用性、可扩展性等特点;Kafka支持高吞吐量、分布式部署等特性,适合大数据处理和流式计算。

代码实现

3.1 引入依赖

    </dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-amqp</artifactId>
    </dependency>

3.2 rabbitmq网站新建队列queue

3.3 模块中配置application.yml

spring:
  rabbitmq:
    host: 192.168.***.***
    port: 5672
    username: admin
    password: 123
logging:
  level:
    com.****.mq: debug

3.4 生产者实现类

@Service
public class ProducerServiceImpl implements IProducerService {
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public void sendMessage(String msg) {
        System.out.println("准备发送数据到mq:" + msg);
        rabbitTemplate.convertAndSend("my_simple_queue", msg);
    }

    @Override
    public void sendUser(User user) {
        System.out.println("准备发送User对象数据到mq:" + user);
        rabbitTemplate.convertAndSend("my_simple_queue",user);
    }
}

3.5 单元测试,发送msg到rabbitmq的队列(my_simple_queue)

3.6 消费者实现类

@Service
public class ConsumerServiceImpl implements IConsumerService {

   //@RabbitListener(queues = "my_simple_queue")
    @Override
    public void consumerMessage(String msg) {
        System.out.println("[消费者:]消费mq中的信息:" + msg);
    }

    @RabbitListener(queues = "my_simple_queue")
    @Override
    public void consumerUser(User user) {
        System.out.println("[消费者:]消费mq中的user信息:" + user.getUsername());
    }
}

3.7 从rabbitmq队列(my_simple_queue)消费数据

3.8 队列的配置类

@Configuration
public class RabbitMQConfig {

    @Bean
    public MessageConverter messageConverter(){
        return new Jackson2JsonMessageConverter();
    }

    @Bean
    public RabbitTemplate rabbitTemplate(ConnectionFactory connectionFactory){

        RabbitTemplate rabbitTemplate = new RabbitTemplate(connectionFactory);
        //将对象转换为json对象形式
        rabbitTemplate.setMessageConverter(messageConverter());
        return rabbitTemplate;

    }

}

小结

总之,生产者-消费者模型是一种重要的并发编程模型,在Java中和消息队列中都得到了广泛的应用。通过合理地使用同步机制和消息队列,可以提高系统的性能、可靠性和扩展性,实现高效的数据传输和处理。此模型在很多领域都有广泛应用,例如任务调度、消息队列、事件驱动编程等,它能有效地解耦数据生成与处理的过程,并提高系统的可扩展性和资源利用率。

参考:

java生产消费者模式 java实现生产者消费者模型_mob6454cc6c8549的技术博客_51CTO博客

Java多线程之生产者和消费者模型 - 简书

生产者消费者模型(学习笔记)——java多线程典型案例_java写生产者消费者模型_未跑路的汪汪的博客-CSDN博客

Java多线程之生产者消费者模式详解_java_脚本之家


感谢阅读,码字不易,多谢点赞!如有不当之处,欢迎反馈指出,感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1150805.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

E1基于线性表的图书管理系统

需求分析 【提示&#xff1a;以无歧义的陈述说明程序设计的任务&#xff0c;主要说明内容是程序要做什么。并明确规定&#xff1a;(1) 输入的形式和输入值的范围&#xff1b;(2) 输出的形式&#xff1b;(3) 程序所能达到的功能。】 图书信息管理&#xff1a; 定义一个包含图…

C/C++网络编程基础知识超详细讲解第二部分(系统性学习day12)

懒大王感谢大家的关注和三连支持~ 目录 前言 一、UDP编程 UDP特点&#xff1a; UDP框架: UDP函数学习 发送端代码案例如下&#xff1a; 二、多路复用 前提讲述 select poll 三、图解如下 总结 前言 作者简介&#xff1a; 懒大王敲代码&#xff0c;…

OpenLayers实战,OpenLayers解析渲染TopoJson格式区划边界数据和实现鼠标经过高亮显示区划边界和文字

专栏目录: OpenLayers实战进阶专栏目录 前言 本章使用OpenLayers实现从vue项目中加载assets资源目录中的TopoJson格式数据,解析渲染TopoJson格式行政区划边界数据,并且实现鼠标经过区域高亮显示区划边界和文字的功能。 本章是综合应用,为方便大家理解代码,拆分为简单的…

强化学习中的值函数

一、值函数 几乎所有的强化学习算法都涉及到估计值函数——状态&#xff08;或状态-动作对&#xff09;的函数&#xff0c;这些函数估计代理处于给定状态&#xff08;或在给定状态下执行给定动作&#xff09;的好坏。这里的“好坏”概念是根据可以预期的未来奖励来定义的&#…

动手学深度学习 - 学习环境配置

学习环境配置 1、安装 Miniconda1.1 下载 miniconda31.2 环境变量配置1.3 安装成功测试1.4 配置文件1.5 使用conda创建、使用、删除环境1.6 conda 常用命令 2、使用 miniconda 安装 d2l2.1 下载 d2l 安装包2.2 安装 d2l 1、安装 Miniconda 参考&#xff1a; https://www.jb51.n…

云尘-JIS-CTF-VulnUpload

继续做渗透 一样给了c段 开扫 存在一个站点 去看看 扫一下吧 第一个flag出来了 存在robots.txt 去看看 admin 页面源代码 第二个flag和账号密码 登入 就一个上传点 这不明显死了哈哈哈哈哈哈哈 直接开喽 上传修改后缀一气呵成 发现只有success 但是我们刚刚robots存在uploa…

十五、redis的使用

目录 一、简介1.1 nosql介绍1.2 redis特性1.3 redis优势1.4 redis应用场景 二、安装2.1 Macos下安装2.2 Linux下安装2.4 客户端连接2.5 切换数据库 三、数据库操作3.1 string类型3.2 键的操作3.3 Hash类型3.4 list类型3.5 set类型3.6 zset类型 四、和python交互4.1 安装redis包…

3.2每日一题(定积分求抽水做工问题)

1、画图&#xff0c;把题目的容器画出来&#xff1a;球形容器&#xff0c;半径为R 2、根据容器的形状进行分析&#xff1a; 抽水的实质是不同深度的水抽出去走的位移是不一样的>抽水的过程 &#xff1a; &#xff08;1&#xff09;先考虑深度为 x到xdx 的薄层水抽出去做多少…

草料资料库丨2023年全国消防宣传月资料合集,免费下载

2023年11月9日是第32个全国消防日&#xff0c;国务院安委会办公室决定于11月份在全国开展消防宣传月活动&#xff0c;主题是“预防为主&#xff0c;生命至上”。 结合今年消防安全月相关要求&#xff0c;我们特邀 注册安全工程师 邵悦 为大家整理了2023年全国消防宣传月的资料…

2023-在mac下安装Homebrew的国内镜像

mac安装Homebrew的国内镜像 尝试使用其他下载源&#xff1a;GitHub 可能会受到访问限制&#xff0c;尝试使用其他镜像或下载源。您可以使用清华大学、中科大或阿里云的 Homebrew 镜像&#xff0c;以提高下载速度和可靠性。例如&#xff0c;可以使用阿里云的镜像来安装 Homebre…

myCobot 320 APP 控制技术案例

引言 机械臂是现代工业和科研领域中的重要工具&#xff0c;它们在制造业、医疗、农业、教育等多个领域都有广泛的应用。这些机器臂不仅可以进行精密操作&#xff0c;而且能够在人类无法进入的危险环境中工作&#xff0c;大大提高了工作效率和安全性。然而&#xff0c;传统的机械…

UE5 日记(人物连招:蒙太奇动画通知(含视频链接))

教程https://www.youtube.com/watch?vsWpENaVGj2M&listPLiSlOaRBfgkcPAhYpGps16PT_9f28amXi&index10&ppiAQB 相关蓝图 连招逻辑 动画通知类 逻辑分析 1.用户输入 已搭载战斗系统模块,可以收到输入指令 2.连击 第一次攻击&#xff1a; 第一次攻击&#xff0c;…

camtasia studio 2024功能介绍安装教程

Camtasia studio 2024是一款功能强大的屏幕录制和视频编辑软件。它可以帮助用户轻松地记录电脑屏幕上的任何操作&#xff0c;并可以将录制的视频进行编辑和制作成高质量的视频教程、演示文稿、培训课程等。 Camtasia studio 2024具有直观的界面和易于使用的工具&#xff0c;包…

springboot动态数据源【非伪数据源】

说明&#xff1a;本文章的数据源不是在配置文件中配置两个或多个数据源&#xff0c;在业务方面对这些数据源来回切换&#xff0c;本文章中的数据源是可以动态添加&#xff0c;修改&#xff0c;切换的&#xff0c;废话不多说。 先看工程图&#xff1a; 1.pom.xml文件 <?x…

第五章 I/O管理 三、I/O控制方式(程序直接控制、中断驱动方式、DMA方式、通道控制方式)

目录 一、程序直接控制方式 1、以读操作为例 2、CPU的干预 3、数据传送的单位 4、数据的流向 5、优点 6、缺点 二、中断驱动方式 1、定义&#xff1a; 2、CPU干预的频率 3、数据传送的单位 4、数据的流向 5、主要缺点和主要优点 优点: 缺点: 三、DMA方式&#x…

R语言使用surveyCV包对NHANES数据(复杂调查加权数据)进行10折交叉验证

美国国家健康与营养调查&#xff08; NHANES, National Health and Nutrition Examination Survey&#xff09;是一项基于人群的横断面调查&#xff0c;旨在收集有关美国家庭人口健康和营养的信息。 地址为&#xff1a;https://wwwn.cdc.gov/nchs/nhanes/Default.aspx 既往咱们…

世界前沿技术发展报告2023《世界航空技术发展报告》(六)航空动力技术

&#xff08;六&#xff09;航空动力技术 1.军用航空动力技术1.1 美国空军授出下一代自适应推进项目合同1.2 法国完成下一代战斗机发动机原型机地面测试1.3 美国通用电气公司为美国陆军测试首台T901涡轴发动机1.4 美国液体活塞公司研制高功重比重油发动机 2.民用航空动力技术2.…

这样刻《少年强则国强》也行……

孙溟㠭篆刻《少年强则国强 》 这是篆书&#xff0c;隶书&#xff0c;简化字刻法有点意思。 孙溟㠭篆刻《少年强则国强》

信息系统项目管理师教程 第四版【第7章-项目立项管理-思维导图】

信息系统项目管理师教程 第四版【第7章-项目立项管理-思维导图】 课本里章节里所有蓝色字体的思维导图

一文告诉你样机是什么,分享几个常用的样机模板

一个项目的诞生通常需要经历头脑构思、绘制设计和最终着陆。在这个过程中&#xff0c;样机制作往往是在着陆实践之前进行的。俗话说&#xff1a;“样机使用得好&#xff0c;草稿过早”。样机设计是产品或网站最终设计的生动、静态和视觉表现。它为用户提供了一种模拟现实的方式…