多线程学习之生产者和消费者与阻塞队列的关系
生产者和消费者
概述:
生产者消费者问题,实际上主要是包含了两类线程:
- 生产者线程用于生产数据
- 消费者线程用于消费数据
生产者和消费者之间通常会采用一个共享的数据区域,这样就可以将生产者和消费者进行解耦,
两者都不需要互相关注对方的
方法:
Object类的等待和唤醒方法
| 方法名 | 说明 |
|---|---|
| void wait() | 导致当前线程等待,直到另一个线程调用该对象的 notify()方法或 notifyAll()方法 |
| void notify() | 唤醒正在等待对象监视器的单个线程 |
| void notifyAll() | 唤醒正在等待对象监视器的所有线程 |
案例需求:
-
桌子类(Desk):定义表示双吉芝士汉堡数量的变量,定义锁对象变量,定义标记桌子上有无双吉芝士汉堡的变量
-
生产者类(Cooker):实现Runnable接口,重写run()方法,设置线程任务
1.判断是否有双吉芝士汉堡,决定当前线程是否执行
2.如果有双吉芝士汉堡,就进入等待状态,如果没有双吉芝士汉堡继续执行,生产双吉芝士汉堡
3.生产双吉芝士汉堡之后,更新桌子上双吉芝士汉堡状态,唤醒消费者消费双吉芝士汉堡
-
消费者类(Foodie):实现Runnable接口,重写run()方法,设置线程任务
1.判断是否有双吉芝士汉堡,决定当前线程是否执行
2.如果没有双吉芝士汉堡,就进入等待状态,如果有双吉芝士汉堡,就消费双吉芝士汉堡
3.消费双吉芝士汉堡后,更新桌子上双吉芝士汉堡状态,唤醒生产者生产双吉芝士汉堡
-
测试类(Demo):里面有main方法,main方法中的代码步骤如下
创建生产者线程和消费者线程对象
分别开启两个线程
/*** @Author:kkoneone11* @name:Cooker* @Date:2023/8/27 18:55*/
public class Cooker extends Thread{private Desk desk;public Cooker(Desk desk){this.desk = desk;}// 生产者步骤:
// 1,判断桌子上是否有双吉芝士汉堡
// 如果有就等待,如果没有才生产。
// 2,把双吉芝士汉堡放在桌子上。
// 3,叫醒等待的消费者开吃。@Overridepublic void run(){while(true){synchronized (desk.getLock()){if(desk.getCount() == 0){break;}else {if(!desk.isFlag()){System.out.println("厨师正在制作双吉芝士汉堡");//生产双层吉士desk.setFlag(true);//叫醒麦门弟子干饭desk.getLock().notifyAll();}else{try{desk.getLock().wait();}catch (Exception e){e.printStackTrace();}}}}}}
}public class Foodie extends Thread{private Desk desk;public Foodie(Desk desk){this.desk = desk;}// 1,判断桌子上是否有双吉芝士汉堡。
// 2,如果没有就等待。
// 3,如果有就开吃
// 4,吃完之后,桌子上的双吉芝士汉堡就没有了
// 叫醒等待的生产者继续生产
// 双吉芝士汉堡的总数量减一@Overridepublic void run(){while(true){synchronized (desk.getLock()){if(desk.getCount() == 0){break;}else {if(desk.isFlag()){//有双层吉士System.out.println("麦门弟子疯狂炫吧");desk.setFlag(false);desk.getLock().notifyAll();desk.setCount(desk.getCount() -1);}else{//没有双层吉士 等待//使用什么对象当做锁,那么就必须用这个对象去调用等待和唤醒的方法.try {desk.getLock().wait();}catch (Exception e){e.printStackTrace();}}}}}}
}public class Demo {public static void main(String[] args) {Desk desk = new Desk();Foodie f = new Foodie(desk);Cooker c = new Cooker(desk);f.start();c.start();}
}
阻塞队列:
阻塞队列常用于生产者和消费者的场景,生产者是往队列里添加元素的线程,消费者是从队列里拿元素的线程。阻塞队列就是生产者存放元素的容器,而消费者也只从容器里拿元素
阻塞队列继承结构:

常见BlockingQueue的实现类:
- ArrayBlockingQueue: 底层是数组,有界
- LinkedBlockingQueue: 底层是链表,无界.但不是真正的无界,最大为int的最大值
方法:
实例:
public class Demo {public static void main(String[] args) throws Exception {// 创建阻塞队列的对象,容量为 1ArrayBlockingQueue<String> arrayBlockingQueue = new ArrayBlockingQueue<>(1);// 存储元素arrayBlockingQueue.put("双层吉士");// 取元素System.out.println(arrayBlockingQueue.take());System.out.println(arrayBlockingQueue.take()); // 取不到会阻塞System.out.println("程序结束了");}
}
案例需求优化:
不再需要Desk这个类,改用阻塞队列
public class Cooker extends Thread{private ArrayBlockingQueue<String> bd;public Cooker(ArrayBlockingQueue<String> bd) {this.bd = bd;}
// 生产者步骤:
// 1,判断桌子上是否有汉堡包
// 如果有就等待,如果没有才生产。
// 2,把汉堡包放在桌子上。
// 3,叫醒等待的消费者开吃。@Overridepublic void run() {while (true) {try {bd.put("汉堡包");System.out.println("厨师放入一个汉堡包");} catch (InterruptedException e) {e.printStackTrace();}}}
}public class Foodie extends Thread{private ArrayBlockingQueue<String> bd;public Foodie(ArrayBlockingQueue<String> bd) {this.bd = bd;}@Overridepublic void run() {
// 1,判断桌子上是否有汉堡包。
// 2,如果没有就等待。
// 3,如果有就开吃
// 4,吃完之后,桌子上的汉堡包就没有了
// 叫醒等待的生产者继续生产
// 汉堡包的总数量减一while (true) {try {String take = bd.take();System.out.println("吃货将" + take + "拿出来吃了");} catch (InterruptedException e) {e.printStackTrace();}}}}public class Demo {public static void main(String[] args) {ArrayBlockingQueue<String> bd = new ArrayBlockingQueue<>(1);Foodie f = new Foodie(bd);Cooker c = new Cooker(bd);f.start();c.start();}
}
相关文章:
多线程学习之生产者和消费者与阻塞队列的关系
生产者和消费者 概述: 生产者消费者问题,实际上主要是包含了两类线程: 生产者线程用于生产数据消费者线程用于消费数据 生产者和消费者之间通常会采用一个共享的数据区域,这样就可以将生产者和消费者进行解耦, 两…...
JAVA语言代入电商平台api接口拼多多根据关键词获取商品列表示例
拼多多根据关键词获取商品接口的意义; 实现商品搜索:通过关键词搜索商品API接口,电商平台可以为消费者提供一个简单、快捷的商品搜索功能。用户只需输入关键词,就可以得到与该关键词相关的商品列表。 提供便捷的商品搜索服务&…...
Centos7更新glibc2.18
Centos7更新glibc2.18 查看glibc版本下载解压glibc2.18编译安装结果验证 查看glibc版本 # 查看glibc版本 ldd --version下载解压glibc2.18 参考: https://blog.csdn.net/qq_39295044/article/details/86685789 https://blog.csdn.net/myhes/article/details/106923039 # 下载…...
QT初学者该安装qt creator哪个版本?
对于Qt初学者,建议安装最新版本的Qt Creator。Qt Creator是Qt官方提供的集成开发环境(IDE),用于开发Qt应用程序。每个Qt版本都会配套提供对应的Qt Creator版本,确保兼容性和稳定性。同时,选择合适的Qt版本也…...
VR智慧校园资中控管理平台综合提升了课堂教学质量
随着越来越多高校在课堂中引进VR虚拟仿真实训系统,为了方便老师对全班同学进行高效率地管理,VR中控平台应运而生。下面为您详细介绍VR中控平台在课堂教学中的应用优势。 VR中控系统安装在教师总控端,融合了课件、视频、3D动画等丰富的教学资源…...
【Go 基础篇】Go语言中的数组:初识与应用
Go语言以其简洁、高效和强大的特性在编程界广受欢迎。数组作为一种基本的数据结构,在各种应用场景中扮演着重要角色。本文将引入Go语言中的数组,介绍其特点、创建、初始化以及基本应用,为你打开数组的大门。 前言 数组是一种固定大小的数据…...
(vue)el-table 怎么把表格列中相同的数据 合并为一行
(vue)el-table 怎么把表格列中相同的数据 合并为一行 效果: 文档解释: 写法: <el-table:data"tableData"size"mini"class"table-class"borderstyle"width:100%"max-height"760":span-…...
精准高效农业作业,植保无人机显身手
中国作为农业大国,拥有约18亿亩的农田,每年都需要进行种子喷洒和农药施用等农业作业,对于普通农户来说,这是一项耗时耗力的工程,同时,人工喷洒农药极易造成农药慢性中毒,对农民的身体健康产生极…...
大集合拆分成多个小集合
文章目录 1. 场景2. 拆分集合方法(写了三种)3. 格式化打印方法 1. 场景 在数据库批量操作时,有可能数据量过大,不能一次性操作,所以需要将大集合拆分为多个小集合进行多次操作 2. 拆分集合方法(写了三种&…...
linux————LVS集群
目录 一、集群概述 一、负载均衡技术类型 二、负载均衡实现方式 二、LVS结构 一、三层结构 二、架构对象 三、LVS工作模式 四、负载均衡算法 一、静态负载均衡 二、动态负载 五、ipvsadm命令详解 六、LVS配置 一、基础配置 二、实现NAT模型搭建 配置IP地址 安装…...
软考高级系统架构设计师系列论文七十一:论行业应用软件系统的开发规划
软考高级系统架构设计师系列论文七十一:论行业应用软件系统的开发规划 一、软件系统相关知识二、摘要三、正文四、总结一、软件系统相关知识 软考高级系统架构设计师系列之:系统开发基础知识...
vue2 自定义指令,插槽
一、学习目标 1.自定义指令 基本语法(全局、局部注册)指令的值v-loading的指令封装 2.插槽 默认插槽具名插槽作用域插槽 二、自定义指令 1.指令介绍 内置指令:v-html、v-if、v-bind、v-on… 这都是Vue给咱们内置的一些指令,…...
oracle超详细语法和备份工具
oracle基础语法 在 Oracle 开发中,客户端把 SQL 语句发送给服务器,服务器对 SQL 语句进行编译、执行,把执行的结果返回给客户端。常用的SQL语句大致可以分为五类:数据定义语言(DDL),包括 CREAT…...
Redis的持久化机制是什么?各自的优缺点?
Redis拥有两种持久化机制:RDB(Redis Database)和AOF(Append-Only File)。 1.RDB(Redis Database)持久化机制 RDB是Redis的默认持久化方式,它通过将Redis在某个时间点的数据状态保存到磁盘上的二进制文件中。该文件是一个快照(snapshot),包含…...
机器学习:什么是分类/回归/聚类/降维/决策
目录 学习模式分为三大类:监督,无监督,强化学习 监督学习基本问题 分类问题 回归问题 无监督学习基本问题 聚类问题 降维问题 强化学习基本问题 决策问题 如何选择合适的算法 我们将涵盖目前「五大」最常见机器学习任务:…...
算法通关村第5关【白银】| 哈希和栈经典算法题
1.两个栈实现队列 思路:两个栈,一个输入栈,一个输出栈。 当需要输入的时候就往inStack中插入,需要输出就往outStack中输出,当输出栈是空就倒出输入栈的数据到输出栈中,这样就保证了后插入的数据从栈顶倒入…...
CrystalNet .Net VCL for Delphi Crack
CrystalNet .Net VCL for Delphi Crack VCL或更为人所知的可视化组件库是基于一个面向对象的框架,什么是用户对开发人员和事件的Microsoft Windows应用程序的接口。可视化组件库是用对象Pascal编写的。它主要是为使用Borland而开发的,它具有与Delphi以及…...
云计算在线实训系统建设方案
一、 人工智能与云计算系统概述 人工智能(Artificial Intelligence,简称AI)是一种模拟人类智能的科学和工程,通过使用计算机系统来模拟、扩展和增强人类的智能能力。人工智能涉及多个领域,包括机器学习、深度学习、自然…...
C++ 珠心算测验
珠心算是一种通过在脑中模拟算盘变化来完成快速运算的一种计算技术。珠心算训练, 既能够开发智力,又能够为日常生活带来很多便利,因而在很多学校得到普及。 某学校的珠心算老师采用一种快速考察珠心算加法能力的测验方法。他随机生成一个正整…...
prometheus+cadvisor监控docker容器
一、安装cadvisor docker pull google/cadvisor:latest二、运行容器 docker run -d \--volume/:/rootfs:ro \--volume/var/run:/var/run:rw \--volume/sys:/sys:ro \--volume/var/lib/docker/:/var/lib/docker:ro \--publish8088:8080 \--detachtrue \--namecadvisor \--priv…...
linux之kylin系统nginx的安装
一、nginx的作用 1.可做高性能的web服务器 直接处理静态资源(HTML/CSS/图片等),响应速度远超传统服务器类似apache支持高并发连接 2.反向代理服务器 隐藏后端服务器IP地址,提高安全性 3.负载均衡服务器 支持多种策略分发流量…...
java_网络服务相关_gateway_nacos_feign区别联系
1. spring-cloud-starter-gateway 作用:作为微服务架构的网关,统一入口,处理所有外部请求。 核心能力: 路由转发(基于路径、服务名等)过滤器(鉴权、限流、日志、Header 处理)支持负…...
树莓派超全系列教程文档--(61)树莓派摄像头高级使用方法
树莓派摄像头高级使用方法 配置通过调谐文件来调整相机行为 使用多个摄像头安装 libcam 和 rpicam-apps依赖关系开发包 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 配置 大多数用例自动工作,无需更改相机配置。但是,一…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...
镜像里切换为普通用户
如果你登录远程虚拟机默认就是 root 用户,但你不希望用 root 权限运行 ns-3(这是对的,ns3 工具会拒绝 root),你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案:创建非 roo…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
Pinocchio 库详解及其在足式机器人上的应用
Pinocchio 库详解及其在足式机器人上的应用 Pinocchio (Pinocchio is not only a nose) 是一个开源的 C 库,专门用于快速计算机器人模型的正向运动学、逆向运动学、雅可比矩阵、动力学和动力学导数。它主要关注效率和准确性,并提供了一个通用的框架&…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
AI+无人机如何守护濒危物种?YOLOv8实现95%精准识别
【导读】 野生动物监测在理解和保护生态系统中发挥着至关重要的作用。然而,传统的野生动物观察方法往往耗时耗力、成本高昂且范围有限。无人机的出现为野生动物监测提供了有前景的替代方案,能够实现大范围覆盖并远程采集数据。尽管具备这些优势…...
MFC 抛体运动模拟:常见问题解决与界面美化
在 MFC 中开发抛体运动模拟程序时,我们常遇到 轨迹残留、无效刷新、视觉单调、物理逻辑瑕疵 等问题。本文将针对这些痛点,详细解析原因并提供解决方案,同时兼顾界面美化,让模拟效果更专业、更高效。 问题一:历史轨迹与小球残影残留 现象 小球运动后,历史位置的 “残影”…...
