生产者消费者案例

article/2025/9/12 15:47:14

目录

  • 前言
  • 一、案例描述
  • 二、创建快递柜
  • 三、创建生产者类
  • 四、创建消费者类
  • 五、测试类
  • 总结


前言

生产者消费者模式属于一种经典的多线程协作的模式,弄清生产者消费者问题能够让我们对于多线程编程有更深刻的理解,下面,为大家分享一个生产者消费者的案例。


一、案例描述

这里以快递为例,假设有一个快递柜,用来存快递,然后有快递员和取件人,快递员往快递柜里存快递,取件人从快递柜中取走快递。快递员作为生产者,取件人作为消费者,当两者在一个时间段同时进行多次自己的操作时,很明显这就是多线程编程的生产者消费者实例了。在这里,我们希望快递员(生产者)存入一个快递,取件人(消费者)就拿走一个快递,如果快递还没有被取走,那么生产者应该等待,而如果快递柜里没有快递,则消费者应该等待。

首先来明确一下,这个案例我们需要准备:

  1. 快递柜类(Box):包含一个成员变量,表示快递的序号,并提供存快递和取快递的操作方法
  2. 生产者类(Producer):实现Runnable接口,包含存快递的方法
  3. 消费者类(Customer):实现Runnable接口,包含取快递的方法
  4. 测试类(BoxDemo):测试类按如下步骤实现这个案例
    (1) 创建快递柜对象作为共享数据区域
    (2) 创建生产者,把快递柜对象作为参数传递至构造方法,因为生产者需要完成存快递的操作
    (3)创建消费者,把快递柜作为对象传递至构造方法,因为消费者需要完成取快递的操作
    (4)创建两个线程,将生产者和消费者对象分别作为参数传递至线程的构造方法,然后启动线程

下面是具体实现:

二、创建快递柜

代码如下:

public class Box {//定义成员变量表示第几个快递(快递序号)private int express;//定义一个成员变量用于表示快递柜的状态private boolean flag = false;//存快递public synchronized void put(int express) {//如果有快递,那么快递员应该等待取件人来取快递if (flag) {try {wait();} catch (InterruptedException e) {e.printStackTrace();}}//如果没有快递,那么快递员就存入快递this.express = express;System.out.println("快递员将第" + this.express + "个快递存入了快递柜");//别忘了存完修改快递柜的状态flag = true;//修改完快递柜状态后,唤醒其他在等待的线程notifyAll();}//取快递public synchronized void get() {//如果有快递,那么取件人就取走快递if (flag) {System.out.println("取件人取出了第" + this.express + "个快递");flag = false;notifyAll();} else {//没有快递,那么取件人就等待try {wait();} catch (InterruptedException e) {e.printStackTrace();}}}
}

说明:

如之前的分析,我们创建了一个Box类当做快递柜,除了表示快递序号的成员变量以外和对应的存快递、取快递方法外,还包括一个用来标记快递柜状态的变量,因为线程执行时需要这个标记来判断是该执行还是等待。存快递和取快递的方法都加上了sychronized变成了同步方法,因为用于等待的wait()方法和唤醒的notifyAll()方法要在sychronized块中使用,否则会抛出 IllegalMonitorStateException异常而无法执行。

三、创建生产者类

代码如下:

public class Producer implements Runnable{private Box b;public Producer(Box b){this.b = b;}@Overridepublic void run() {for(int i = 1 ;i<11;i++){b.put(i);}}
}

说明:

快递员当做生产者类,它实现了Runnable接口,重写了run()方法,并且有一个Box类型的成员变量,和一个以这个成员变量为参数的构造方法,因为在这个类中要调用存快递的操作。在这里,run()方法里一共存入了10次快递。

四、创建消费者类

代码如下:

public class Customer implements Runnable{private Box b ;public Customer(Box b){this.b = b;}@Overridepublic void run() {while(true){b.get();}}
}

说明:

同生产者类一样,消费者(取件人)类也实现了Runnable接口,重写了run()方法,同样有一个Box类型的成员变量,和一个以这个成员变量为参数的构造方法,因为这个类里会调用取快递的操作。由于能取快递的次数是由生产者(快递员)存入多少快递决定的,所以这里我们直接用while循环就好了。

五、测试类

在测试类中,我们分别创建快递柜、生产者和消费者的对象,将快递柜对象作为参数分别传入生产者和消费者创建时的构造方法。然后创建两个线程,分别将生产者和消费者对象作为构造方法的参数传递,最后启动线程,观察结果。

代码如下:

public class BoxDemo {public static void main(String[] args) {//创建快递柜对象Box box = new Box();//创建生产者和消费者对象Producer p = new Producer(box);Customer c = new Customer(box);//创建两个线程Thread t1 = new Thread(p,"生产者线程");Thread t2 = new Thread(c,"消费者线程");//启动线程t1.start();t2.start();}
}

执行结果:
在这里插入图片描述
可以看到,快递员和取件人有序地完成了10个快递的存和取。


总结

以上就是一个简单的生产者和消费者的案例,从这里面我们可以看出,这种模式除了生产者、消费者以外,还有一个很重要的中介的数据缓存区,也就是案例中的快递柜,生产者往里面“丢”,消费者从里面“拿”,这样三者才构成了完整的生产者消费者模式。



http://chatgpt.dhexx.cn/article/hT4iR9l5.shtml

相关文章

JAVA多线程之生产者消费者模型

生产者消费者模型 所谓的生产者消费者模型&#xff0c;是通过一个容器来解决生产者和消费者的强耦合问题。通俗的讲&#xff0c;就是生产者在不断的生产&#xff0c;消费者也在不断的消费&#xff0c;可是消费者消费的产品是生产者生产的&#xff0c;这就必然存在一个中间容器&…

Linux生产者消费者模型

文章目录 生产者消费者模型生产者消费者模型的概念生产者消费者模型的特点生产者消费者模型优点 基于BlockingQueue的生产者消费者模型基于阻塞队列的生产者消费者模型模拟实现基于阻塞队列的生产消费模型 生产者消费者模型 生产者消费者模型的概念 生产者消费者模式就是通过一…

生产者消费者模型你知道多少

背景 进入正题之前先说点故事。从最开始学java的那里开始&#xff1a;我是从08年下半年开始学Java&#xff0c;在《我的六年程序之路》中提到了一些。当时比较简单&#xff0c;每天看尚学堂的视频&#xff08;对于初学者而言看视频好一些。&#xff09;&#xff0c;然后写代码。…

生产者消费者模型详解

生产者消费者模型 文章目录 生产者消费者模型什么是生产者消费者模型基于BlockingQueue的生产者消费者模型单生产者单消费者模型多生产者多消费者模型 什么是生产者消费者模型 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接…

Python -- 生产者消费者

代码 # -*- coding: utf-8 -*- # Author : markadc # Time : 2021/4/14 11:43from queue import Queue import time import threading# maxsize: 指定队列最大长度 q Queue(maxsize10)# 生产者 def product(name):count 0while True:# 只要队列没有满&#xff0c;就一直…

生产者与消费者

生产者和消费者 目录 生产者和消费者1.什么是生产者和消费者2.生产者和消费者(不加唤醒机制)3.生产者和消费者(加唤醒机制)4.解决虚假唤醒5.使用lock锁6.面试题 1.什么是生产者和消费者 ​ 在日常生活中&#xff0c;我们去商店买东西&#xff0c;我们就是消费者&#xff0c;商…

三种方式实现生产者-消费者模型

前言 生产者消费者问题&#xff08;英语&#xff1a;Producer-consumer problem&#xff09;&#xff0c;也称有限缓冲问题&#xff08;英语&#xff1a;Bounded-buffer problem&#xff09;&#xff0c;是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的…

生产者消费者模型

目录 一、生产者消费者模型的概念 二、生产者消费者模型的特点 三、生产者消费者模型优点 四、基于BlockingQueue的生产者消费者模型 4.1 基本认识 4.2 模拟实现 五、POSIX信号量 5.1 信号量概念 5.2 信号量函数 5.2.1 初始化信号量 5.2.2 销毁信号量 5.2.3 等待信…

打家劫舍问题

打家劫舍问题 最近碰见这种问题实在是太多了,感觉还是有必要学习一下打家劫舍以及其变种问题这一类问题采用的都是动态规划的解法 一些练习题目 6378. 最小化旅行的价格总和 198. 打家劫舍I 213. 打家劫舍 II 337. 打家劫舍 III 2560. 打家劫舍 IV 1 、打家劫舍I 题目…

经典动态规划:打家劫舍系列问题

打家劫舍系列总共有三道&#xff0c;难度设计非常合理&#xff0c;层层递进。第一道是比较标准的动态规划问题&#xff0c;而第二道融入了环形数组的条件&#xff0c;第三道更绝&#xff0c;让盗贼在二叉树上打劫. House Robber | public int rob(int[] nums);题目很容易理解…

【算法】动态规划(三)——打家劫舍系列问题

目录 一、前言 二、打家劫舍 &#xff08;1&#xff09;198. 打家劫舍Ⅰ • 整体代码&#xff1a; &#xff08;2&#xff09;213. 打家劫舍 II • 题目分析 • 整体代码&#xff1a; &#xff08;3&#xff09;337. 打家劫舍Ⅲ • 思路分析 • 整体代码&#xff1a; 三、补充知…

动态规划之打家劫舍系列

前言 打家劫舍问题是一种非常经典的有限制条件的动态规划问题&#xff0c;按理说&#xff0c;不是一种特殊的类型&#xff0c;但是因为力扣上纯纯的出了三道题&#xff08;1&#xff0c;2&#xff0c;3&#xff09;来考察&#xff0c;题目的难度是依次递进的&#xff0c;还结合…

动态规划之打家劫舍

动态规划之打家劫舍 文章目录 动态规划之打家劫舍1. "198. 打家劫舍"2. "198. 打家劫舍&#xff08;变种&#xff1a;输出路径&#xff09;"3. "213. 打家劫舍 II"4. "337. 打家劫舍 III" 1. “198. 打家劫舍” dp数组定义&#xff1a…

oracle 根据部分字段去重

问题&#xff1a;在oracle中使用group by分组&#xff0c;group by子句中必须包含所有的select中的字段和order by子句中的字段。 在不使用group by子句的情况下&#xff0c;进行分组。&#xff08;根据部分字段分组&#xff09; over()分析函数 原sql SELECTIM. ID mediaGrou…

oracle字段去重查询,oracle怎么去重查询

oracle去重查询的方法是&#xff1a; oracle 数据库多字段去重 方法介绍&#xff1a;distinct 关键字、group by 、row_number ()over(partition by 列 order by 列 desc) 我的需求是&#xff1a;根据某几列去重 查询出去重后的全部信息。最后我选择的是第三种方法。 我的想法&…

oracle 数据去重方法

1. 创建表&#xff1a; -- Create table create table TEST_USER (user_id NUMBER(3),user_name VARCHAR2(20),user_age NUMBER(3) ) tablespace GUAN_TABLESPACEpctfree 10initrans 1maxtrans 255storage(initial 64Knext 1Mminextents 1maxextents unlimited);--测试数据…

oracle 字符串去重

select regexp_replace(1,1,3,5,5, ([^,])(,\1)*(,|$), \1\3) from dual;注意&#xff1a; 但是&#xff0c;这个去重&#xff0c;必须建立在排序的基础上&#xff0c;如果listagg拼接出来的数值像 a, b, a, c 这时候&#xff0c;该正则就会失效。

MYSQL/ORACLE多字段去重-根据某字段去重

通过百度上的答案多数无效 自己搞了个 使用oracle row_number()函数&#xff0c;给每个同名的加一个序号&#xff0c;最后筛选第n个想同的即可 oracle与mysql不同 1.oracel 多字段distinct(字段名去重) group by去重失效 可以用row_number() over(partition) 给同名列加个序号…

Oracle 数据去重

在Oracle数据库中删除重复数据 一&#xff0c;查询及删除重复记录的SQL语句 Person01表&#xff1a; 1. 查询表中多余的重复数据&#xff0c;根据ID字段来判断是否重复 SELECT * FROM PERSON01 WHERE ID IN (SELECT ID FROM PERSON01 GROUP BY ID HAVING COUNT(ID) > 1)…

Oracle根据多列去重

&#xff08;1&#xff09;distinct 关键词 distinct用于返回唯一不同的值&#xff0c;可作用于单列和多列 但必须将其放在开头&#xff0c;否则会提示错误 而若在其后添加多个变量名&#xff0c;则返回的将是这多个变量名不同时重复的列&#xff0c;因而使用distinct筛选某…