阻塞队列:线程安全与生产者消费者模型解析
一、阻塞队列
阻塞队列就是基于普通队列做出扩展
1.线程安全的
如果针对一个已经满了的队列进行入队列,此时入队列操作就会阻塞,一直阻塞到队列不满(其他线程出队列元素)之后
如果针对一个已经空了的队列进行出队列,此时出队列操作就会阻塞,一直阻塞到队列不空(其他线程入队列元素)之后
包饺子
A和B和C在过年期间要包饺子,为了快一点三个人决定一起包饺子
但包饺子得先擀饺子皮,现在就只有一个擀面杖,所以A擀饺子皮是BC就陷入了阻塞,显然这就会出现竞争擀面杖问题(锁竞争)。
我们加入了一个桌子(阻塞队列),A负责擀饺子皮,BC通过桌子来包饺子,
如果A干的特别快,BC赶不上他的速度,很快桌子就会被放满(队列满了),这下A就会停下来(阻塞)
如果BC干的特别快,A赶不上他俩的速度,桌子为空(队列为空),BC就得等待(阻塞)
生产者消费者模型
1.引入生产者消费者模型,就可以更好的做到“解耦合”
上述过程中,A和B,A和C的耦合性较强,如果B或者C挂了,对于A的影响是很大的
加了阻塞队列A和B,C几乎几乎就没有交集了,B,C就算是挂了,对于A的影响也是微乎其微
阻塞队列(消息队列)
1.上述的阻塞队列,是基于这个数据结构实现的服务器程序,又被部署到单独的主机上
2.整个系统的结构更复杂了,你要维护的服务器更多了
3.效率,请求从A发过来B受到,这个过程经过转发要有一定开销
2.削峰填谷
当外网的请求数量就像洪水一样,急剧增加,这时A的请求数量就会增加很多,即使工作一般比较简单,每个请求消耗的资源少,但架不住多。B和C完成的工作更复杂,消耗的资源更多,这就可能导致BC挂了。
我们加入了阻塞队列之后
队列就像抗洪用的水库,只是用来存储数据的,消耗资源很少,抗压能力很强,在数据多的时候,存下来保持稳定的速度,少的是否就会放出数据,同样保持稳定请求速度,需要注意的是这个队列只是防止BC挂掉了。
Java标准库提供了现成的阻塞队列数据结构
使用put 和 offer一样都是入队列
但是put是带有阻塞功能,offer 没带阻塞(队列满了会返回结果)
take 方法用来出队列,同样带有阻塞功能
阻塞队列没有提供带有阻塞功能的获取队首元素的方法
尝试实现一个阻塞队列
既然涉及到了出队列,那数据结构就得用到循环队列,保证空间利用率
class MyBlockingQueue{private String[] elems = null;private int head = 0;private int tail = 0;private int size = 0;//准备锁对象,使用this也可以private Object locker = new Object();public MyBlockingQueue(int capacity){elems= new String[capacity];}public void put(String elem) throws InterruptedException {while(size >= elems.length){}//新的元素要放到tail指向的位置上elems[tail] = elem;tail++;if(tail >= elems.length){tail = 0;}size++;}public String take() throws InterruptedException {String elem = null;while(size == 0){}//取出 head 位置的元素返回elem = elems[head];head++;if(head >= elems.length){head = 0;}size--;return elem;}}
现在我们就相当于实现了一个循环队列,我们需要加上阻塞效果,我们知道只有当队列满和队列空才会阻塞,而解除阻塞则需要队列中有一个元素出去和队列中有一个元素进来。
所以我们可以在put结束时加上notify,并在判断队列满了的时候进行阻塞,至于在判断条件加上while循环,是为了防止在多线程情况下被不小心解锁,毕竟,每次put,take之后都对解一次锁,为了保证代码的原子性,我们为整个方法都加上锁。试想一下如果没有这么加锁,就会引发数组越界等一系列问题。
take方法也是同理
至此我们可以来验证一下阻塞队列是否成功,我们创建了两个线程分别是t1,t2,t1线程为生产元素的线程并且要比t2线程消费元素快的多。
Thread t1 = new Thread(() -> {int n = 1;while(true){try {queue.put(n + "");System.out.println("生产元素" + n);n++;} catch (InterruptedException e) {throw new RuntimeException(e);}}});//消费者Thread t2 = new Thread(() -> {while (true){try {String n = queue.take();System.out.println("消费元素" + n);Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}}});t2.start();t1.start();
我们发现在一开始运行时,t1线程十分快都到了一千多了,但t2线程才到2,这就导致了t1线程要想继续添加元素,就得等t2线程,这就出现了消费一个元素,就生产一个元素。
定时器
public class ThreadDemo30 {public static void main(String[] args) {Timer timer = new Timer();timer.schedule(new TimerTask() {@Overridepublic void run() {//时间到了之后要执行的代码System.out.println("hello timer 3000");}},3000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello timer 2000");}}, 2000);timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println("hello timer 1000");}},1000);System.out.println("hello main");}
}
我们发现进程并没有结束,Timer 里内置了前台线程
实现一个简单timer
要想实现定时器,得先剖析它,怎么剖析呢,我们发现定时器就像一个容器一样将线程存储起来,等线程的时间到了就调度,时间短的限制性,这个容器我们就可以用
优先级队列
而优先级队列存储的是啥呢?优先级队列比较器基准是啥呢?
存储的这个元素得有时间和进程,这时没问题的,我们主要的是根据时间来做文章,首先便是初始化问题,时间得是相对时间所以我们发现
在构造方法上我们是现在的时间加上等待的时间、
其次就是比较器
我们比较的基准是时间,时间少的往前走反之往后走,
比较的顺序往往是试出来的,而不是去猜出来的
回到优先级队列那里,我们要有一个方法创建任务对象,并且将任务放入队列中
接下来是进行任务的时刻
我们将代码放到构造方法中
我们得有一个线程来做遍历队列中任务的工作
我们之所以加上了锁
是因为防止线程安全问题出现,试着想一下没有锁会咋样,可能队列中都没有元素了它还进行访问,可能队列中的这个元素都出去来,还去执行
为了保持原子性还是得加上锁的,在漫长的等待后,队列进入元素,locker重新获得锁,需要注意的是我们每次去往队列添加一个元素都会解锁。之后我们得获取当前时间和任务规定的时间进行计较,如果没达到约定时间就要进行等待。
至此我们就完成了定时器的设计了,我们发现做完后好像云里雾里啊,我们来重新画图梳理
首先
因为定时是时间越短越先执行,所以我们用优先级队列来存储线程
我们存储的元素不仅要有线程还要有时间,并且还要有比较器
我们元素构建好了得把元素放到队列中就衍生出了schdule方法,它负责创建对象,并将对象放入队列
接下来我们就要执行进程,我们选在了构造方法里
一进来就先加锁,防止出现线程安全问题,然后判断是否为空,如果为空就要等待,等schdule方法放入对象,并notify。
然后比较当前时间和任务预期执行时间,没到预期时间就去等待相应时间、
到达时间出队列,并且运行线程。
结束!!!
相关文章:
阻塞队列:线程安全与生产者消费者模型解析
一、阻塞队列 阻塞队列就是基于普通队列做出扩展 1.线程安全的 如果针对一个已经满了的队列进行入队列,此时入队列操作就会阻塞,一直阻塞到队列不满(其他线程出队列元素)之后 如果针对一个已经空了的队列进行出队列,…...
【时时三省】(C语言基础)用函数实现模块化程序设计
山不在高,有仙则名。水不在深,有龙则灵。 ----CSDN 时时三省 为什么要用函数? 已经能够编写一些简单的C程序,但是如果程序的功能比较多,规模比较大,把所有的程序代码都写在一个主函数(main函数)中&#x…...
基于CATIA参数化圆锥建模的自动化插件开发实践——NX建模之圆锥体命令的参考与移植(一)
引言 在CATIA二次开发领域,Python因其灵活性和丰富的库支持逐渐成为高效工具开发的首选语言。本文将以笔者开发的CATIA锥体自动化建模工具为例,参考NX软件中高效锥体创建命令,深度解析基于PySide6 GUI框架与pycatia接口库的集成…...
天才简史——Paolo Fiorini与他的速度障碍法
一、背景 第一次“认识”Paolo Fiorini教授是看了DMP的体积避障论文《Dynamic Movement Primitives: Volumetric Obstacle Avoidance》,而且他的学生Michele Ginesi将相关代码开源了,后来查阅了Paolo Fiorini相关资料才发现他竟然是速度障碍法的作者&am…...
第五天的尝试
目录 一、每日一言 二、练习题 三、效果展示 四、下次题目 五、总结 一、每日一言 毅力是永久的享受。 没有人是一座孤岛,每个人都是这块大陆的一部分。 二、练习题 import numpy as np import matplotlib.pyplot as plt array np.array([1,2,3,4,5]) plt.plot…...
大小端模式和消息的加密解密
大小端模式 知识点一 什么是大小端模式 // 大端模式 // 是指数据的高字节保存在内存的低地址中 // 而数据的低字节保存在内存的高地址中 // 这样的存储模式有点儿类似于把数据当作字符串顺序处理 // 地址由小向大增加,数据从高位往低位放 …...
(1) 查看端口状态
1. lsof 和 netstat 命令的区别 1.1 lsof 概念:只有在 root 的命令下才能执行,否则无内容显示;root 命令下显示完全 lsof -i: 8080 1.2 netstat 普通用户下显示不完全,root 命令下显示完全 netstat -tunlp | grep 8080 1.3…...
【C++]string模拟实现
#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include<iostream> #include<assert.h> using namespace std; namespace liu {class string{public:using iterator char*;using const_iterator const char*;//string();//无参构造 string(const string&…...
Linux动静态库制作与原理
什么是库 库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常。 本质上来说库是一种可执行代码的二进制形式,可以被操作系统…...
ArkUI Tab组件开发深度解析与应用指南
ArkUI Tab组件开发深度解析与应用指南 一、组件架构与核心能力 ArkUI的Tabs组件采用分层设计结构,由TabBar(导航栏)和TabContent(内容区)构成,支持底部、顶部、侧边三种导航布局模式。组件具备以下核心特…...
winrar 工具测试 下载 与安装
https://zhuanlan.zhihu.com/p/680852417 https://www.angusj.com/resourcehacker/#download 点击String Table,在展开列表中找到80:2052展开,删除1277行。点击右上方编译按钮,并保存。...
代码随想录算法训练营第四十四天
卡码网题目: 99. 岛屿数量100. 岛屿的最大面积 其他: 今日总结 往期打卡 99. 岛屿数量 跳转: 99. 岛屿数量 学习: 代码随想录公开讲解 问题: 给定一个由 1(陆地)和 0(水)组成的矩阵,你需要计算岛屿的数量。岛屿由水…...
每日Prompt:自拍生成摇头娃娃
提示词 将这张照片变成一个摇头娃娃:头部稍微放大,保持面部准确,身体卡通化。[把它放在书架上]。...
制作我的计算器
1. 界面布局 新建项目 MyCalculator,开始布局。 2. 静态布局 代码如下: // etc/pages/Index.ets Entry Component struct Index {build() {Column() {/*** 运算区*/Column() {TextInput({ text: 12x13 }).height(100%).fontSize(32).enabled(false).f…...
如何查看 Ubuntu开机是否需要密码
要查看 Ubuntu 开机是否需要密码,可以通过以下方法进行判断: 1. 检查自动登录设置 图形界面操作: 进入系统设置(Settings)→ 用户账户(User Accounts)→ 解锁设置(输入当前用户密码…...
今日行情明日机会——20250519
上证指数缩量收十字星,个股涨多跌少,这周反弹的概率比较大。 深证指数缩量调整,临近反弹,个股表现更好。 2025年5月19日涨停股主要行业方向分析 并购重组(政策驱动资产整合) • 涨停家数:16…...
【CodeBuddy 】从0到1,让网页导航栏变为摸鱼神器
【CodeBuddy 】从0到1,让网页导航栏变为摸鱼神器 我正在参加CodeBuddy「首席试玩官」内容创作大赛,本文所使用的 CodeBuddy 免费下载链接:腾讯云代码助手 CodeBuddy - AI 时代的智能编程伙伴 🌟嗨,我是LucianaiB&#…...
PCL点云库点云数据处理入门系列教材目录(2025年5月更新....)
PCL点云库点云数据处理入门系列教材目录 基础阶段 第 1 讲:PCL库简介和安装(Win10/11VS2019PCL 1.12.0)第 2 讲:PCL库中点云基本知识和数据类型结构第 3 讲:PCL库中点云数据格式PCD和PLY及其输入输出(IO&…...
同一颗太阳:Australia、Austria、Arab、Africa、Augustus、August、Aurora、Athena
我们来看一下下面这一堆单词: Australia n.澳大利亚;澳洲 Australian n.澳大利亚人 a.澳大利亚的 Austria n.奥地利 Austrian n.奥地利人 a.奥地利(人)的 Africa n.非洲 African n.非洲人* Arab a.阿拉伯的;阿拉伯人的 n.阿拉伯人(pl.Arabs)…...
用户账号及权限管理:企业安全的基石与艺术
在当今数字化时代,用户账号及权限管理已成为企业IT安全体系中不可或缺的核心组件。它不仅是保护敏感数据的第一道防线,更是确保业务运营效率和合规性的关键。本文将深入探讨用户账号及权限管理的重要性、最佳实践以及实施策略,助您构建一个安全、高效且灵活的访问控制体系。…...
存储系统03——数据缓冲evBuffer
存储系统03——数据缓冲evBuffer 数据缓冲evBuffer分段存储零拷贝线程安全 evbuffer 实例——存储系统事件触发 数据缓冲evBuffer evbuffer 是 Libevent 提供的一个高效内存缓冲区管理工具,用于存储和操作数据。它类似于一个动态增长的字节缓冲区,支持多…...
留给王小川的时间不多了
王小川,这位头顶“天才少年”光环的清华学霸、搜狗输入法创始人、中国互联网初代技术偶像,正迎来人生中最难啃的硬骨头。 他在2023年创立的百川智能,被称为“大模型六小虎”之一。今年4月,王小川在全员信中罕见地反思过去两年工作…...
Python海龟绘图-斗地主
#导入库 import random as r import turtle as t #数据 pk[红心A,红心2,红心3,红心4,红心5,红心6,红心7,红心8, 红心9,红心10,红心J,红心Q,红心K,黑桃A,黑桃2,黑桃3,黑桃4,黑桃5,黑桃6,黑桃7,黑桃8, 黑桃9,黑桃10,黑桃J, 黑桃Q,黑桃K,方块A,方块2,方块3,方块4,方块5,方块6,方块…...
一、内存调优
一、内存调优 什么是内存泄漏 监控Java内存的常用工具 内存泄露的常见场景 内存泄露的解决方案 内存泄露与内存溢出的区别 内存泄露:在Java中如果不再使用一个对象,但是该对象依然在GC ROOT的引用链上,这个对象就不会被垃圾回收器回收&…...
机器学习--特征工程具体案例
一、数据集介绍 sklearn库中的玩具数据集,葡萄酒数据集。在前两次发布的内容《机器学习基础中》有介绍。 1.1葡萄酒列标签名: wine.feature_names 结果: [alcohol, malic_acid, ash, alcalinity_of_ash, magnesium, total_phenols, flavanoi…...
Java-List集合类全面解析
Java-List集合类全面解析 前言一、List接口概述与核心特性1.1 List在集合框架中的位置1.2 List的核心特性1.3 常见实现类对比 二、ArrayList源码剖析与应用场景2.1 内部结构与初始化2.2 动态扩容机制2.3 性能特点与最佳实践 三、LinkedList 源码剖析与应用场景3.1 内部结构与节…...
在Cursor中启用WebStorm/IntelliJ风格快捷键
在Cursor中启用WebStorm/IntelliJ风格快捷键 方法一:使用预置快捷键方案 打开快捷键设置 Windows/Linux: Ctrl K → Ctrl SmacOS: ⌘ K → ⌘ S 搜索预设方案 在搜索框中输入keyboard shortcuts,选择Preferences: Open Keyboard Shortcuts (JSON) …...
32、跨平台咒语—— React Native初探
一、时空晶体架构(核心原理) 1. 量子组件桥接协议 // 原生组件映射 <View> → iOS UIView / Android ViewGroup <Text> → UILabel / TextView 魔法特性: • JavaScriptCore引擎:通过V8/Hermes引擎执行JS逻辑…...
无源探头衰减比与带宽特性的关联性研究
引言 在电子测量领域,无源探头作为示波器的重要附件,其性能参数直接影响测量结果的准确性。本文将从电路设计原理出发,深入分析衰减比与带宽这两个关键参数的相互关系,帮助工程师正确理解并选择适合的测量探头。 技术原理分析 …...
虚拟机的三个核心类加载器
虚拟机的三个核心类加载器 在Java虚拟机(JVM)中,类加载器(ClassLoader)负责将类的字节码加载到内存中,并生成对应的Class对象。以下是三个核心类加载器的详细说明: 1. 启动类加载器(Bootstrap ClassLoader) 职责: 加载Java核心类库(如java.lang、java.util等),位…...
国家互联网信息办公室关于发布第十一批深度合成服务算法备案信息的公告
wenz 根据《互联网信息服务深度合成管理规定》,现公开发布第十一批境内深度合成服务算法备案信息,具体信息可通过互联网信息服务算法备案系统(https://beian.cac.gov.cn)进行查询。任何单位或个人如有疑议,请发送邮件…...
深入理解动态规划:从斐波那契数列到最优子结构
引言 动态规划(Dynamic Programming, DP)是算法设计中一种非常重要的思想,广泛应用于解决各类优化问题。许多看似复杂的问题,通过动态规划的视角分析,往往能找到高效的解决方案。本文将系统介绍动态规划的核心概念,通过经典案例展…...
AT 指令详解:基于 MCU 的通信控制实战指南AT 指令详解
在 MCU(单片机)项目中,我们经常需要与各种通信模组(GSM、Wi-Fi、蓝牙等)交互。而这类模组通常都通过串口(UART)与 MCU 通信,控制它们的“语言”就是——AT 指令。 一、什么是 AT 指…...
初学c语言16(内存函数)
1.memcpy 形式: 功能:完成内存块拷贝(所以可拷贝任何类型的数据) 过程:从source开始拷贝num个字节的数据到destination指向的空间里 返回值:返回目标空间的起始地址 应用: 模拟实现…...
【git进阶】git rebase(变基)
文章目录 合并分支提交信息修改合并提交记录时间问题1时间问题2时间问题3git rebase有很多用武之地,我一一道来 合并分支 当多人协作同一个分支时,在提交我们自己版本之前,我们会先用git pull获取远端最新的版本。但是 git pull = git fetch + git mergegit merge是一个非…...
Pytorch---view()函数
在PyTorch中,view函数是一个极为重要的张量操作函数,其主要功能是对张量的形状进行重塑,与此同时会尽力维持张量中元素的总数不变。 1. 基本功能与语法 view函数的主要作用是改变张量的维度和大小,不过要保证重塑前后张量的元素…...
AI Agent开发第71课-一个完善的可落地企业AI Agent全架构
开篇 在之前的若干篇章里我们大量叙述了DIFY AI工作流、重排序、提示词重写、文档chunk、AI翻页、各种高级RAG应用以及AI Agent案例甚至全代码的输出。 目的,就是为了帮助大家认识到这么一件事,那就是: 当前AI主要还是在被叫好却不卖座,很多人(包括我身边的太多大厂)去…...
Prompt、Agent、MCP关系
AI基础概念概述 链接: https://www.bilibili.com/video/BV1aeLqzUE6L?t419.4 Agent(智能体):智能体是能够执行特定任务的程序或实体,它可以根据环境变化调整自身行为。 MCP(多通道协议):MCP是…...
人工智能100问☞第27问:神经网络与贝叶斯网络的关系?
神经网络与贝叶斯网络是两种互补的智能模型:神经网络通过多层非线性变换从数据中学习复杂模式,擅长大规模特征提取和预测,而贝叶斯网络基于概率推理建模变量间的条件依赖关系,擅长处理不确定性和因果推断。两者的融合(如贝叶斯神经网络)结合了深度学习的表征能力与概率建…...
Vue-样式绑定-style
样式绑定-style 对象写法数组写法 对象写法 :style"{fontSize: x}", x是动态值 ({fontSize: x}是样式对象) 代码 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8" /><title>…...
Python60日基础学习打卡D30
回顾: 导入官方库的三种手段导入自定义库/模块的方式导入库/模块的核心逻辑:找到根目录(python解释器的目录和终端的目录不一致) # 直接导入 from random import randint print(randint(1, 10)) # 导入自定义库 import module m…...
el-upload图片设置了url不显示问题
引用:可以使用Image组件测试url是否可以用 此时不显示图片,因为打印后提示图片加载失败 此时图片显示 使用的base64的格式。但要注意在生成的base64码前要加上data:image/png;base64的内容才可以赋值给url...
学习黑客PowerShell的历史、架构与工作原理深度解析
PowerShell的历史、架构与工作原理深度解析 🔍 作者: 海尔辛 | 发布时间: 2025-05-19 12:28:44 UTC 1. PowerShell的历史演变 📜 🔹 诞生背景与起源 PowerShell的诞生源于微软解决Windows管理工具碎片化问题的需求。在PowerShell出现之前…...
视觉-和-语言导航的综述:任务、方法和未来方向
22年6月来自UC Santa Cruz、澳大利亚的阿德莱德大学和 USC 的论文“Vision-and-Language Navigation: A Survey of Tasks, Methods, and Future Directions”。 人工智能研究的一个长期目标是构建能够用自然语言与人类交流、感知环境并执行现实世界任务的智体。视觉与语言导航…...
JUC入门(四)
ReadWriteLock 代码示例: package com.yw.rw;import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock;public class ReadWriteDemo {public static void main(String[] args) {MyCache myCache new MyCache…...
day 21 常见降维算法
一、无监督降维 定义:这类算法在降维过程中不使用任何关于数据样本的标签信息(比如类别标签、目标值等)。它们仅仅根据数据点本身的分布、方差、相关性、局部结构等特性来寻找低维表示。 输入:只有特征矩阵 X。 目标:…...
代理IP高可用性与稳定性方案:负载均衡、节点健康监测与智能切换策略
一、负载均衡策略:动态分配与场景适配 多算法协同调度 轮询与加权轮询:适用于定时数据采集等低频任务,通过静态IP池按顺序分配请求,避免单一节点过载。例如,静态IP池可支持电商商品价格监控,按固定周期切换…...
C语言:在操作系统中,链表有什么应用?
在操作系统中,链表是一种重要的数据结构,凭借其灵活的内存管理和高效的插入/删除特性,被广泛应用于多个核心模块。以下是其主要应用场景及详细说明: 1. 内存管理:空闲内存块管理 应用场景:操作系统需要管…...
RocketMQ
一、引言 Message Queue(消息 队列),从字⾯上理解:⾸先它是⼀个队列。FIFO先进先出的数据结构——队列。消息队列就是所谓的存放消息的队列。 消息队列解决的不是存放消息的队列的⽬的,解决的是通信问题。 …...
学习BI---QuickBI介绍
BI是什么 BI 数据仓库(存数据) OLAP(多维分析) 数据挖掘(找规律) 可视化(图表/看板) 人话解释就是把企业里乱七八糟的数据变成老板能看懂的报告,帮他们做更聪明的决…...