阻塞队列、生产者消费者模型、阻塞队列的模拟实现等干货

文章目录

  • 💐生产者消费者模型
  • 💐模拟实现阻塞队列
    • 💡注意点一
    • 💡注意点二

阻塞队列是一种“特殊”的数据结构,但是也遵循队列的“先进先出”特性,它的特殊在于:

阻塞队列的两个特性:

1、阻塞队列是线程安全的

2、带有阻塞特性:

​ a.向队列中添加元素时,如果队列满了,就会阻塞等待,直到其他线程从队列中取走元素时才会解除等待

​ b.从队列中向外拿元素时,如果队列为空,就会阻塞等待,直到其他线程向队列中添加元素后,才会解除等待

阻塞队列的最大作用就是可以用来实现“生产者消费者模型”;

💐生产者消费者模型

什么是生产者消费者模型?

比如,在过年时包饺子,妈妈负责擀饺子皮,我负责包饺子,妈妈会把擀好的饺子皮放在板子上,此时,我就可以拿饺子皮开始包饺子,当板子上没有饺子皮时,我就要等妈妈擀,如果当板子上的饺子皮满了的时候,妈妈就会停止擀饺子皮,等到板子上有位置了以后,才会继续擀,所以,妈妈就相当于是一个生产者,我就相当于是一个消费者,放饺子皮的板子就相当于是一个阻塞队列。

1、生产者消费者模型可以解决强耦合问题:

什么是强耦合:

例如,有一个简单的分布式系统,客户端向服务器机房发送一个要求后等待服务器响应,但是,这个要求可能需要两个服务器联合进行处理,假设,有一个A服务器和B服务器,A服务器可能需要B服务器的响应后再进行后序的处理,但是呢,如果因为B服务器挂了,那么就会导致A服务器也会挂,所以这种联系较紧密的强耦合模块就很容易出现问题;

在这里插入图片描述

针对上述情况,就可以引入一个阻塞队列来解决:

将阻塞队列也封装成一个单独的服务器程序,让A服务器直接和这个阻塞队列进行交互,让B服务器也直接和阻塞队列进行交互,不管B到底会不会出错,也都不会影响到A,A都只会和阻塞队列进行交互,就算以后再增加多个服务器的话,也就只是和阻塞队列进行交互,A也不必进行修改,这样就降低了耦合性👇

在这里插入图片描述

2、削峰填谷

”峰“的意思是:短时间内,请求量比较多

”谷”的意思是:请求量比较少

如果在没有引入阻塞队列的情况下(如上图一),如果客户端这边的请求量比较大,那么,不管A接受多少请求量,都会直接发给B,A和B所要承受的压力是一样的,但是,每个服务器都是不一样的,可能就会出现,对于这个并发量,A服务器可以承受,B服务器就承受不了;

对于这种情况就可以用生产者消费者模型解决:

和图二一样,给A发过去的请求量,并不直接发给B,而是发队列,B仍然按照他自己的速度处理请求,举个例子:假如,A和B每秒钟可以处理1000条请求,但是,出现了极端情况,A每秒处理了3000条请求,但是呢,B仍然会继续按照每秒处理1000条请求,这样,请求就会在队列中积压,如果队列满了的话,A向队列中发送请求就发生阻塞,直到B从队列中取出请求,使队列出现空余空间后,A再继续发出请求,就这样,一来一回,虽然可能响应有点慢了,但是总比把B服务器搞挂了好;而后续A服务器发出的请求量少了以后,B服务器就可以慢慢的处理完这些积压的请求;

有了这样的机制后,就可以保证在突发情况突然来临时,服务器仍然能够正常运行

💐模拟实现阻塞队列

class MyBlockingQueue<T> {private Object[] element = new Object[5];//为了避免内存可见性问题,加上一个volatileprivate volatile int head;//记录当前要弹出元素的位置private volatile int tail;//记录当前要添加元素的位置private  volatile int size;//向队列中添加一个元素public void put(T elem) {//加锁synchronized(this) {//判断队列是否满了while(size == element.length) {//阻塞等待try {this.wait();} catch (InterruptedException e) {e.printStackTrace();}}//没满情况element[tail] = elem;tail++;//判断tail是否是数组最后一个元素if(tail == element.length){tail = 0;}size++;this.notify();}}//弹出队列中的一个元素public T take() {synchronized (this) {//判断队列是否为空while(size == 0) {//阻塞等待try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}//不为空情况T ret = (T)element[head];head++;if(head == element.length) {head = 0;}size--;this.notify();return ret;}}}

💡注意点一

在这里插入图片描述

put() 方法里面的wait需要take()里面的notify唤醒,take()方法里面的wait需要put() 里面的notify唤醒,因为,当在put里面调用wait后,就会处于阻塞等待,就算是继续调用put,仍然会阻塞等待,必须调用take里面的notify后,才后解除等待,take也同理,所以不可能出现方法内调用notify解除方法自己的wait这中情况;

💡注意点二

在这里为什么要使用while循环判断?

在这里插入图片描述

wait被唤醒的方式除了notify外,还有一种方式就是,如果在其他线程中调用interupt方法可能会中断wait的等待,就如上面代码一样,如果一旦调用了interupt方法,那么wait就会被唤醒,被唤醒之后,代码并没有退出,这时候,如果数组仍然是满的话,那么就会出现bug,此时的tail指向的还是一个有效元素,这个有效元素就会被修改,并且size++,size就超过了数组的长度,所以,利用while语句,一旦wait被唤醒,那么就再次进行一下判断,如果数组是满的,仍然继续等待,反之向下执行,take也同理;

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

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

相关文章

【C++入门】引用

目录 6.引用 6.1引用概念 6.2引用的写法 6.3引用的特性 6.4常引用 6.5引用的使用场景 6.5.1引用做参数 6.5.2引用做返回值❗❗ &#x1f387;值做返回值 &#x1f387;引用做返回值 &#x1f387;引用在顺序表做返回值 6.5.3传值、传引用效率比较(参数&#xff0…

【OpenGL的着色器03】内置变量和函数(gl_Position等)

目录 一、说明 二、着色器的变量 2.1 着色器变量 2.2 着色器内置变量 三、最常见内置变量使用范例 3.1 常见着色器变量 3.2 示例1&#xff1a; gl_PointSize 3.3 示例2&#xff1a;gl_Position 3.4 gl_FragColor 3.5 渲染点片元坐标gl_PointCoord 3.6 gl_PointCoo…

Android Gradle开发与应用 (三) : Groovy语法概念与闭包

1. Groovy介绍 Groovy是一种基于Java平台的动态编程语言&#xff0c;与Java是完全兼容&#xff0c;除此之外有很多的语法糖来方便我们开发。Groovy代码能够直接运行在Java虚拟机&#xff08;JVM&#xff09;上&#xff0c;也可以被编译成Java字节码文件。 以下是Groovy的一些…

图像处理与视觉感知---期末复习重点(1)

文章目录 一、概述二、图像处理基础2.1 视觉感知要素2.2 像素间的一些基本关系2.2.1 相邻像素2.2.2 连通性2.2.3 距离度量 2.3 基本坐标变换2.4 空间变换与灰度值 一、概述 1. 图像的概念及分类。  图像是用各种观测系统以不同形式和手段观测客观世界而获得的、可以直接或间接…

nodejs版本管理工具nvm安装和环境变量配置

1、下载nvm.exe https://github.com/coreybutler/nvm-windows/releases2、安装 1.在D盘根目录新建一个dev文件夹&#xff0c;在dev里面再新建一个nodejs。 2.双击下载好的nvm.exe 修改文件路径&#xff0c;且路径中不能有中文 3.安装完成后在D:\dev\nvm打开settings.txt&…

kerberos学习系列一:原理

1、简介 Kerberos 一词来源于古希腊神话中的 Cerberus —— 守护地狱之门的三头犬。 Kerberos 是一种基于加密 Ticket 的身份认证协议。Kerberos 主要由三个部分组成&#xff1a;Key Distribution Center (即KDC)、Client 和 Service。 优势&#xff1a; 密码无需进行网络传…

Docker数据卷篇

1. 数据卷&#xff08;容器数据管理&#xff09; 引言&#xff1a;在之前的nginx案例中&#xff0c;修改nginx的html页面时&#xff0c;需要进入nginx内部。并且因为没有编辑器&#xff0c;修改文件也很麻烦。 这就是因为容器与数据&#xff08;容器内文件&#xff09;耦合带…

Scrapy与分布式开发(3):Scrapy核心组件与运行机制

Scrapy核心组件与运行机制 引言 这一章开始讲解Scrapy核心组件的功能与作用&#xff0c;通过流程图了解整体的运行机制&#xff0c;然后了解它的安装与项目创建&#xff0c;为后续实战做好准备。 Scrapy定义 Scrapy是一个为了爬取网站数据、提取结构性数据而编写的应用框架…

Claude3荣登榜首,亚马逊云科技为您提供先行体验!

Claude3荣登榜首&#xff0c;亚马逊云科技为您提供先行体验&#xff01; 个人简介前言抢先体验关于Amazon BedrockAmazon Bedrock 的功能 Claude3体验教程登录Amazon Bedrock试用体验管理权限详细操作步骤1.提交应用场景详细信息2.请求模型的访问权限3.请求成功&#xff0c;开始…

Mybatis实现分页查询数据(代码实操讲解)

在MyBatis中实现分页查询的常见方式有两种&#xff1a;使用MyBatis内置的分页插件如PageHelper&#xff0c;或者手动编写分页的SQL语句。下面我将为你提供两种方式的示例代码。 使用PageHelper分页插件 首先&#xff0c;确保你的项目中已经添加了PageHelper的依赖。在Maven项…

overleaf latex 笔记

overleaf: www.overleaf.com 导入.tex文件 1.代码空一行&#xff0c;代表文字另起一段 2. 1 2 3 排序 \begin{enumerate} \item \item \item \end{enumerate} 3.插入图片 上传图片并命名 \usepackage{float}导包\begin{figure}[H]&#xff1a;表示将图…

【网络安全】漏洞挖掘入门教程(非常详细),小白是如何挖漏洞(技巧篇)0基础入门到精通!

温馨提示&#xff1a; 初学者最好不要上手就去搞漏洞挖掘&#xff0c;因为漏洞挖掘需要很多的系统基础知识和一些理论知识做铺垫&#xff0c;而且难度较大…… 较合理的途径应该从漏洞利用入手&#xff0c;不妨分析一些公开的CVE漏洞。很多漏洞都有比较好的资料&#xff0c;分…

【四】【SQL Server】如何运用SQL Server中查询设计器通关数据库期末查询大题

数据库学生选择1122 数据库展示 course表展示 SC表展示 student表展示 数据库学生选课1122_3 第十一题 第十二题 第十三题 第十四题 第十五题 数据库学生选课1122_4 第十六题 第十七题 第十八题 第十九题 第二十题 数据库学生选课1122_5 第二十一题 第二十二题 结尾 最后&…

保留数据的重装系统教程!(win10系统)

上车警告&#xff01;&#xff01;&#xff01; 本教程无需思考&#xff0c;跟着操作一步一步来就能完成系统的重装。原理是将C盘系统重装&#xff0c;其他盘符数据保存。适用于系统盘重装数据或更改系统版本。 重要提示&#xff01;&#xff01;&#xff01; C盘有重要学习资…

Long-term Correlation Tracking LCT目标跟踪算法原理详解(个人学习笔记)

目录 1. 算法总览2. 算法详解2.1. 基础相关滤波跟踪2.2. 各模块详解2.2.1. 相关跟踪2.2.2. 在线检测器 3. 算法实现3.1. 算法步骤3.2. 实现细节 4. 相关讨论&总结 1. 算法总览 LCT的总体流程如上图所示&#xff0c;其思想为&#xff1a;将长时跟踪&#xff08;long-term tr…

第五节 JDBC驱动程序类型

JDBC驱动程序是什么&#xff1f; JDBC驱动程序在JDBC API中实现定义的接口&#xff0c;用于与数据库服务器进行交互。 例如&#xff0c;使用JDBC驱动程序&#xff0c;可以通过发送SQL或数据库命令&#xff0c;然后使用Java接收结果来打开数据库连接并与数据库进行交互。 JDK…

18.四数之和

题目&#xff1a;给你一个由 n 个整数组成的数组 nums &#xff0c;和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若两个四元组元素一一对应&#xff0c;则认为两个四元组重复&#xff09;&#x…

每日一题 — 有效三角形的个数

611. 有效三角形的个数 - 力扣&#xff08;LeetCode&#xff09; 思路&#xff1a; 双指针思想&#xff0c;先将数据排序 然后先固定最大的数Max&#xff0c;也就是数组最后的数再定义一左一右两个下标 left 、 right&#xff0c;当这个值相加大于最大的数&#xff0c;那么他两…

Pytorch学习 day05(RandomCrop、Transforms工具使用总结)

RandomCrop 将PIL或Tensor格式的输入图片&#xff0c;随机裁剪指定尺寸的部分输入尺寸可以为序列或单个整形数字代码如下&#xff1a; from PIL import Image from torchvision import transforms from torch.utils.tensorboard import SummaryWriterimg Image.open("i…

python高级之元类

python高级之元类 一、Type创建类1、传统方式创建类2、非传统方式 二、元类三、总结 一、Type创建类 class A(object):def __init__(self, name):self.name namedef __new__(cls, *args, **kwargs):data object.__new__(cls)return data根据类创建对象 objA(‘kobe’) 1、执…