【多线程】阻塞队列
1. 认识阻塞队列和消息队列
阻塞队列也是一个队列,也是一个特殊的队列,也遵守先进先出的原则,但是带有特殊的功能。
如果阻塞队列为空,执行出队列操作,就会阻塞等待,阻塞到另一个线程往阻塞队列中添加元素(队列不空)为止
如果阻塞队列满了,执行入队列操作,就会阻塞等待,阻塞到另一个线程从阻塞队列中取出元素(队列不满)为止
上述这两条特性,希望大家能有个好的认识,有了这两条特性,也是我们后续模拟实现一个阻塞队列的基础。
消息队列也是一个特殊的队列,在阻塞队列的基础上,加上了一个 "消息类型",按照指定的类型进行先进先出。
注意这里我们谈到的消息队列仍然是一个数据结构。
由于消息队列很好用,因此就有业内牛人,把这样的数据结构,单独实现成了一个程序,这个程序,可以通过网络的方式和其他程序进行通信,类似于 MySQL 这样的客户端。
此时由于单独实现了一个程序,此时这个消息队列就能单独的部署到一组服务器上,此时存储能力和转发能力都大大提升了,在很多大型的项目里,都能看到这样的消息队列的身影,于是消息队列就能和 MySQL,redis 相提并论了,成为了一个重要的组件,称为 "中间件"。
行内常见的消息队列有:rabbit mq,active mq,rocket mq,kafka......
如何理解消息队列呢?这里用一个形象的例子来介绍:
假设你是个渣男帅哥,追你的妹子排起了很长的队伍,有可爱类型的,有高冷类型的,有憨憨类型的...
你每天都要找一个妹子约会,于是你今天发个说说:想跟我约会的妹子,来我家门口排好队等我吧,于是喜欢你的妹子纷纷来到了你家门口:
假设你今天上午想找一个憨憨类型的妹子去约会,那么就需要从排队的人中选一个憨憨类型的妹子出来,但是排在最前面的并不是憨憨类型的妹子,但是不影响,因为你今天的规划,就是憨憨类型的妹子优先级最高!
那么排队的妹子中,有两个憨憨类型的妹子,选哪个呢?这次就是按照顺序来了!谁先来,你选谁!
假设你上午睡过头了呢?家门口排满了,此时还想等你的妹子就只能等着,等下次了,假设没有妹子等你呢?那你就得坐在家门口等妹子嘛,这也是类似于阻塞队列的效果,队列为空,或者队列为满的情况。
上述这样的例子,就类似于消息队列,队列中每个元素都有类型,按照指定类型遵循先进先出的原则!
2. 生产者消费者模型
2.1 认识生产者消费者模型
为啥消息队列香?因为他和阻塞队列特性关系非常大。
而阻塞队列的一个典型应用场景就是 "生产者消费者模型",这是一种非常典型的开发模型。
这里我们也通过一个生活中的例子来理解生产者消费者模型:
不知道大家有没有包过饺子,这里把包饺子抽象成两个步骤:擀饺子皮,包饺子。
此时有小明,小强,小王,小李这四个人一起包饺子,怎么包呢?有两个可选方案:
每个人分别擀自己的饺子皮,自己包
小明负责擀饺子皮,擀完后放在盘子里,小强,小王,小李从盘子中取饺子皮负责包饺子。
那么方案二就类似于生产者消费者模型:
擀饺子皮的人:生产者
盘子:阻塞队列/消息队列
取饺子皮包饺子的人:消费者
如果小明擀的慢,盘子上没有饺子皮了,其他人就得等着,如果小明擀的快,盘子上饺子皮放满了,小明就得等着,不要擀了。
这里与我们前面说的阻塞队列满/阻塞队列空的情况相互对应上了!
2.2 阻塞队列实际中的实用
有了上面的例子,我们再来结合实际中开发的情况,进一步了解阻塞队列/消息队列在实际开发中的实用吧:
服务器之间的调用:
假设现在有一个客户端程序(游戏),需要充值钻石了,没有使用阻塞队列/消息队列的情况:
上述没有使用阻塞队列的情况,就是属于耦合太高了,写代码通常追求高内聚,低耦合,高耦合指的是什么呢?
高耦合:两个程序之间关联太高了,如果一方出现问题可能会影响另一方。
就比如上述情况,服务器A 想给服务器B 发送请求(调用B),必须知道 B 的存在,如果 服务器B 挂了,是有可能引起服务器A 的 BUG 的!此时如果还需要增加一个存放充值日志的服务器C,那么 服务器A 的代码是要进行调整的,对于程序猿来说,显然不喜欢麻烦!
那么这样的场景,使用生产者消费者模型就能有效的降低耦合,让两个服务器之间的关联变低。
引入消息队列:
这样一来,服务器A 和 服务器B 之间就没多大的关系了,服务器A 只需要知道往哪个队列放,从哪个队列取,服务器B 也是同理,而且在实现服务器A 的代码中,没有一行与服务器B 相关的代码,实现服务器B 的代码中,也没有一行与服务器 A 相关的代码。
此时耦合就被大大的降低了,如果服务器B 挂了,对服务器A 是没有影响的,此时如果 A 从队列中取,发现没有结果,就可以视为充值失败,这样一来,就可以排查 B 的问题了。
同时利用生产者消费者模型,还可以有效控制请求的访问量,不至于一下子并发太高了,把服务器B 给搞挂了,就比如之前鹿晗官宣的时候,此时用户发送的请求量是不可预估的,而利用生产者消费者模型就能很好的解决这个问题。
3. 模拟实现一个阻塞队列
Java 本身也是给我们提供了阻塞队列的:BlockingQueue 这是一个接口,实现这个接口的有如下类:
LinkedBlockingQueue 基于链表实现的阻塞队列
PriorityBlockingQueue 基于堆实现的阻塞队列
ArrayBlockingQueue 基于数组实现的阻塞队列
阻塞队列本身是一种特殊的队列,就是在普通队列上引入阻塞的功能,主要的阻塞方法有两个:
入队列:put
出队列:take
想要实现一个阻塞队列,就需要先实现一个普通的队列,然后再将这个队列改造成带有阻塞功能的队列即可。
对于普通队列的实现,我们可以采取链表,数组的方式,这里我们就基于数组的结构来实现(环形队列)。
实现环形队列,我们需要区分队列满了,和队列空的两种情况。
初始的时候,head 和 tail 指向同一个位置,当插入元素的时候在 tail 位置插入,然后 tail++ 即可,出元素的时候,head++即可,所以当 head == tail 的时候,队列为空。
那么问题来了:
此时队列是满的,但是 head == tail 条件也成立!这样一来我们就无法判断队列为空,还是队列满了。
有两种解决方案:
浪费一个空间上述当 tail 走到 5 下标位置就判断满了
定一个 size 变量,记录当前队列中元素个数
这里我们就采用 size 来记录队列中元素个数吧:
public class MyArrayBlockQueue<T> {private T[] elem;private int head;private int tail;private int size;public MyArrayBlockQueue(int capacity) {elem = (T[])new Object[capacity];head = 0;tail = 0;size = 0;}public void put(T value) {// 如果队列满了, 则不能插入元素if (size == elem.length) {return;}elem[tail++] = value;// 防止 tail 越界, 修正 tail 位置if (tail >= elem.length) {tail = 0;}size++;}public T take() {// 如果队列为空, 则不能出队列if (size == 0) {return null;}T result = elem[head++];// 防止 head 越界if (head >= elem.length) {head = 0;}size--;return result;}
} 最基本的环形队列我们就写好了,接下来就要在这个基础上,增加阻塞功能,保证多线程情况下的线程安全问题。
public synchronized void put(T value) throws InterruptedException {// 如果队列满了, 则阻塞等待while (size == elem.length) {this.wait();}elem[tail++] = value;// 防止 tail 越界, 修正 tail 位置if (tail >= elem.length) {tail = 0;}size++;// 唤醒 take() 中的 wait, 告诉他队列不为空, 可以出队列了this.notify();}public synchronized T take() throws InterruptedException {T result;// 如果队列为空, 则也需要阻塞等待while (size == 0) {this.wait();}result = elem[head++];// 防止 head 越界if (head >= elem.length) {head = 0;}size--;// 唤醒 put() 中的 wait, 告诉他队列没有满, 可以入队列了this.notify();return result;} 这样就能保证线程安全了,上述我们把队列满和空的情况时使用的 if 替换成了 while,这是因为在 Java 标准中,表述了使用 wait 方法可能会中断,存在虚假唤醒的情况,建议使用 wait 方法时,应该在循环内使用。
有了这个阻塞队列,大家就能多创建几个线程,利用阻塞队列模拟包饺子的场景了,这里我就不提供代码了。
下期预告:【多线程】模拟实现定时器
相关文章:
【多线程】阻塞队列
1. 认识阻塞队列和消息队列 阻塞队列也是一个队列,也是一个特殊的队列,也遵守先进先出的原则,但是带有特殊的功能。 如果阻塞队列为空,执行出队列操作,就会阻塞等待,阻塞到另一个线程往阻塞队列中添加元素(…...
python2升级python3
查看当前版本 [roottest-01 node-v18.16.0]# python -V Python 2.7.5 安装依赖 [roottest-01 node-v18.16.0]# yum install -y gcc gcc-c zlib zlib-devel readline-devel 已加载插件:fastestmirror, langpacks Loading mirror speeds from cached hostfile * base…...
Apache Hudi初探(八)(与spark的结合)--非bulk_insert模式
背景 之前讨论的都是’hoodie.datasource.write.operation’:bulk_insert’的前提下,在这种模式下,是没有json文件的已形成如下的文件: /dt1/.hoodie_partition_metadata /dt1/2ffe3579-6ddb-4c5f-bf03-5c1b5dfce0a0-0_0-41263-0_202305282…...
Java之旅(九)
Java 循环语句 Java 中的循环语句包括 for、while 和 do-while,它们都可以用于实现循环结构。 for 语句用于循环执行一段代码块,直到给定的条件表达式的布尔值为 false。 for 语句的一般格式如下: for (initialization; condition; update…...
6年测试经验之谈,为什么要做自动化测试?
一、自动化测试 自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。 个人认为,只要能服务于测试工作,能够帮助我们提升工作效率的,不管是所谓的自动化工具,还是简单的SQL 脚本、批处理脚本,还是自己编写…...
二分法的边界条件 2517. 礼盒的最大甜蜜度
2517. 礼盒的最大甜蜜度 给你一个正整数数组 price ,其中 price[i] 表示第 i 类糖果的价格,另给你一个正整数 k 。 商店组合 k 类 不同 糖果打包成礼盒出售。礼盒的 甜蜜度 是礼盒中任意两种糖果 价格 绝对差的最小值。 返回礼盒的 最大 甜蜜度。 记录一…...
java设计模式(十六)命令模式
目录 定义模式结构角色职责代码实现适用场景优缺点 定义 命令模式(Command Pattern) 又叫动作模式或事务模式。指的是将一个请求封装成一个对象,使发出请求的责任和执行请求的责任分割开,然后可以使用不同的请求把客户端参数化&a…...
[运维] iptables限制指定ip访问指定端口和只允许指定ip访问指定端口
iptables限制指定ip访问指定端口 要使用iptables限制特定IP地址访问特定端口,您可以使用以下命令: iptables -A INPUT -p tcp -s <IP地址> --dport <端口号> -j DROP请将 <IP地址> 替换为要限制的IP地址,将 <端口号&g…...
JS学习笔记(3. 流程控制)
1. 分歧 1.1 if条件 if (条件) {...} // 为真则执行,单条语句可省略大括号 if (条件) {...} else {...}// 为真则执行if,否则执行else if (条件1) {...} else if (条件2) {...} else {...} // 条件1为真则,条件2为真则,否则执…...
遥感云大数据在灾害、水体与湿地领域典型案例及GPT模型教程
详情点击链接:遥感云大数据在灾害、水体与湿地领域典型案例及GPT模型教程 一:平台及基础开发平台 GEE平台及典型应用案例; GEE开发环境及常用数据资源; ChatGPT、文心一言等GPT模型 JavaScript基础; GEE遥感云重…...
什么是文件描述符以及重定向的本质和软硬链接(Linux)
目录 1 什么是文件?什么是文件操作?认识系统接口open 什么是文件描述符认识Linux底层进程如何打开的文件映射关系重定向的本质理解软硬链接扩展问题 1 什么是文件?什么是文件操作? 文件 文件内容 文件属性(文件属性…...
LVM逻辑卷元数据丢失恢复案例 —— 筑梦之路
Lvm常见的故障主要是pv出现异常,有以下几种情况 一个是pv所在的磁盘发生了lvm的元数据损坏一个是系统无法识别到pv所在的磁盘一个是系统异常,断电等导致重启后盘符发生变化,也就是系统识别的磁盘uuid发生变化,但是wwid还是可以对应…...
Java技术规范概览
Java技术规范 目录概述需求: 设计思路实现思路分析1.Java JSR的部分2.JSR-000373.JSR-0000394.JSR-000337 参考资料和推荐阅读 Survive by day and develop by night. talk for import biz , show your perfect code,full busy,skip hardness,make a bet…...
【OpenMMLab AI实战营第二期】二十分钟入门OpenMMLab笔记
OpenMMlab 主页:openmmlab.com 开源地址:https://github.com/open-mmlab 学习视频地址:https://www.bilibili.com/video/BV1js4y1i72P/ 概述 开源成为人工智能行业发展引擎 时间轴 theano:2007 Caffe:2013 Ten…...
docker-compose单机容器集群编排
docker-compose dockerfile模板文件可以定义一个独立的应用容器,如果需要多个容器就需要服务编排。服务编排有很多技术方案 docker-compose开源的项目实现对容器集群的快速编排 docker-compose将所管理的容器分为三层,分别为工程,服务&#…...
CentOS7 安装Gitlab
1、安装依赖 sudo yum install -y curl openssh-server ca-certificates tzdata perl libsemanage-devel 2、安装邮件服务工具 sudo yum install -y postfix 3、配置GitLab 软件源镜像 curl -fsSL https://packages.gitlab.cn/repository/raw/scripts/setup.sh | /bin/bash …...
Mysql InnoDB的Buffer Pool
Buffer Pool 在MySQL服务器启动的时候就向操作系统申请了⼀⽚连续的内存,他们给这⽚内存起了个名,叫做Buffer Pool(中⽂名 是缓冲池)。 默认情况下Buffer Pool只有128M⼤⼩,最⼩值为5M,通过修改配置文件设…...
SMTP简单邮件传输协议(C/C++ 发送电子邮件)
SMTP是用于通过Internet发送电子邮件的协议。电子邮件客户端(如Microsoft Outlook或macOS Mail应用程序)使用SMTP连接到邮件服务器并发送电子邮件。邮件服务器还使用SMTP将邮件从一个邮件服务器交换到另一个。它不用于从服务器下载电子邮件;相…...
uploads靶场通关(1-11关)
Pass-01(JS校验) 看题目我们准备好我们的php脚本文件,命名为1.php 上传该php文件,发现上传失败 方法一:将浏览器的JavaScript禁用 然后就能上传了 方法二: 查看源码,发现只能上传以下形式的文…...
6.1黄金探底回升是否到顶,今日多空如何布局
近期有哪些消息面影响黄金走势?今日黄金多空该如何研判? 黄金消息面解析:周三(5月31日)黄金期货价格攀升,美国国债收益率下降推动金价升至一周最高收盘位。美市尾盘,现货黄金收报1962.42美元/盎司,上升3…...
synchronized 学习
学习源: https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖,也要考虑性能问题(场景) 2.常见面试问题: sync出…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
【SQL学习笔记1】增删改查+多表连接全解析(内附SQL免费在线练习工具)
可以使用Sqliteviz这个网站免费编写sql语句,它能够让用户直接在浏览器内练习SQL的语法,不需要安装任何软件。 链接如下: sqliteviz 注意: 在转写SQL语法时,关键字之间有一个特定的顺序,这个顺序会影响到…...
React19源码系列之 事件插件系统
事件类别 事件类型 定义 文档 Event Event 接口表示在 EventTarget 上出现的事件。 Event - Web API | MDN UIEvent UIEvent 接口表示简单的用户界面事件。 UIEvent - Web API | MDN KeyboardEvent KeyboardEvent 对象描述了用户与键盘的交互。 KeyboardEvent - Web…...
【配置 YOLOX 用于按目录分类的图片数据集】
现在的图标点选越来越多,如何一步解决,采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集(每个目录代表一个类别,目录下是该类别的所有图片),你需要进行以下配置步骤&#x…...
土地利用/土地覆盖遥感解译与基于CLUE模型未来变化情景预测;从基础到高级,涵盖ArcGIS数据处理、ENVI遥感解译与CLUE模型情景模拟等
🔍 土地利用/土地覆盖数据是生态、环境和气象等诸多领域模型的关键输入参数。通过遥感影像解译技术,可以精准获取历史或当前任何一个区域的土地利用/土地覆盖情况。这些数据不仅能够用于评估区域生态环境的变化趋势,还能有效评价重大生态工程…...
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包
文章目录 现象:mysql已经安装,但是通过rpm -q 没有找mysql相关的已安装包遇到 rpm 命令找不到已经安装的 MySQL 包时,可能是因为以下几个原因:1.MySQL 不是通过 RPM 包安装的2.RPM 数据库损坏3.使用了不同的包名或路径4.使用其他包…...
代理篇12|深入理解 Vite中的Proxy接口代理配置
在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...
R语言速释制剂QBD解决方案之三
本文是《Quality by Design for ANDAs: An Example for Immediate-Release Dosage Forms》第一个处方的R语言解决方案。 第一个处方研究评估原料药粒径分布、MCC/Lactose比例、崩解剂用量对制剂CQAs的影响。 第二处方研究用于理解颗粒外加硬脂酸镁和滑石粉对片剂质量和可生产…...
