阻塞队列(JAVA)

阻塞队列是一种特殊的队列,也遵守 "先进先出" 的原则。

阻塞队列能是一种线程安全的数据结构, 并且具有以下特性:

  • 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素;
  • 当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素。

 JAVA标准库中已经实现了阻塞队列,我们可以直接进行使用

BlockingQueue

BlockingQueue是一个接口,阻塞队列也和普通队列一样有两种实现方式:数组和链表。

注:创建阻塞队列时需要传入队列的长度参数。

BlockingQueue<String> queue = new ArrayBlockingQueue(10);

由于 BlockingQueue继承自Queue所以普通队列的接口也可以正常使用,但是没有阻塞效果。

BlockingQueue提供了两个带有阻塞效果且线程安全的方法:put()和take()。

public static void main(String[] args) throws InterruptedException {//创建一个长度为10的阻塞队列BlockingQueue<String> queue = new ArrayBlockingQueue(10);//入队五次queue.put("1");queue.put("2");queue.put("3");queue.put("4");queue.put("5");//出队列六次System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());//由于此时队列为空,所以会出现阻塞System.out.println(queue.take());
}

为了更好的理解阻塞队列我们可以自己设计一个简单的阻塞队列。

模拟实现

先写一个普通的循环队列

public class MyBlockingQueue {private String[] queue = new String[10];//表示队列内元素数量private int size;//头尾指针private int head;private int tail;//入队列public boolean put(String str) {if (this.size == 10) {//队列满return false;}this.queue[this.tail++] = str;this.tail %= 10;this.size++;return true;}//出队列public String take() {if (this.size == 0) {//队列空return null;}String ret = this.queue[this.head];this.head = (++this.head+10) % 10;this.size--;return ret;}
}

现在它是线程不安全的所以我们应该加锁,因为里面的两个方法几乎每一步都有修改操作所以我们直接给整个方法都加上锁

//入队列
public synchronized boolean put(String str) {……
}
//出队列
public synchronized String take() {……
}

为了防止编译器优化我们对值会被修改的属性都使用volatile进行修饰

public class MyBlockingQueue {private String[] queue = new String[10];//表示队列内元素数量private volatile int size;//头尾指针private volatile int head;private volatile int tail;
}

接下来我们还需加上阻塞的特性即:

  • 当队列满的时候, 继续入队列就会阻塞, 直到有其他线程从队列中取走元素;
  • 当队列空的时候, 继续出队列也会阻塞, 直到有其他线程往队列中插入元素。

我们只需在put()方法判断队列满之后将返回修改为等待即可。

//入队列
public synchronized boolean put(String str) {if (this.size == 10) {//队列满try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}this.queue[this.tail++] = str;this.tail %= 10;this.size++;return true;
}

当任意线程调用take()方法后put()方法就应该继续执行入队操作,所以在tack方法的最后应该加上notify()方法来唤醒线程。

//出队列
public synchronized String take() {if (this.size == 0) {//队列空return null;}String ret = this.queue[this.head];this.head = (++this.head+10) % 10;this.size--;this.notify();return ret;
}

出队列的阻塞也和入队列的阻塞原理相同。

//入队列
public synchronized boolean put(String str) {if (this.size == 10) {//队列满try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}this.queue[this.tail++] = str;this.tail %= 10;this.size++;this.notify();return true;
}
//出队列
public synchronized String take() {if (this.size == 0) {//队列空try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}String ret = this.queue[this.head];this.head = (++this.head+10) % 10;this.size--;this.notify();return ret;
}

wait()和notify()的对应关系如下:

此时代码还是有一个非常隐蔽的BUG。那就是wait()除了可以被notify()唤醒外还可以被 interrupt唤醒所以应该将if判断改为while循环。

//入队列
public synchronized boolean put(String str) {while (this.size == 10) {//队列满try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}……
}
//出队列
public synchronized String take() {while (this.size == 0) {//队列空try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}……
}

测试

public static void main(String[] args) {MyBlockingQueue queue = new MyBlockingQueue();//入队五次queue.put("1");queue.put("2");queue.put("3");queue.put("4");queue.put("5");//出队列六次System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());System.out.println(queue.take());//由于此时队列为空,所以会出现阻塞System.out.println(queue.take());
}

public static void main(String[] args) {MyBlockingQueue queue = new MyBlockingQueue();//入队11次queue.put("1");queue.put("2");queue.put("3");queue.put("4");queue.put("5");queue.put("6");queue.put("7");queue.put("8");queue.put("9");queue.put("10");//由于队列满出现阻塞queue.put("11");
}

在 jconsole 中查看线程状态为WAITING

完整代码 

public class MyBlockingQueue {private String[] queue = new String[10];//表示队列内元素数量private volatile int size;//头尾指针private volatile int head;private volatile int tail;//入队列public synchronized boolean put(String str) {while (this.size == 10) {//队列满try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}this.queue[this.tail++] = str;this.tail %= 10;this.size++;this.notify();return true;}//出队列public synchronized String take() {while (this.size == 0) {//队列空try {this.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}String ret = this.queue[this.head];this.head = (++this.head+10) % 10;this.size--;this.notify();return ret;}
}

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

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

相关文章

【WinForm.NET开发】Windows窗体设计器错误页

本文内容 黄色栏此错误的实例有关此错误的帮助有关此错误的论坛帖子常见设计时错误 如果 Windows 窗体设计器由于代码、第三方组件或其他位置的错误而未能加载&#xff0c;将显示错误页而不是设计器。 此错误页不一定表示设计器中的 bug。 bug 可能位于代码隐藏文件中的某个位…

STM32F4XX的12位ADC采集数值超过4096右对齐模式设置失败

文章目录 一、前言二、问题1&#xff1a;数值超过4096三、问题1的排错过程四、问题2&#xff1a;右对齐模式设置失败五、问题2的解决方法5.1 将ADC_ExternalTrigConv设置为05.2 使用ADC_StructInit()函数 一、前言 最近在学习STM32的ADC功能&#xff0c;遇到了一个奇怪的问题。…

(一)Spring Cloud 直击微服务作用、架构应用、hystrix降级

直击微服务作用 微服务架构: 遇到了什么问题? 将单体架构拆分成微服务架构后,如果保证多个服务(项目)正常运行? 哪个技术可以解决这个问题? 微服务技术 服务治理: 服务管理,维护服务与服务之间的关系 这个技术如何使用? netflix/网…

【研究僧毕业总结】第1024个创作日

目录 前言1. 机缘2. 收获3. 憧憬 前言 收到这封来信&#xff0c;代表从创作至今刚好满足1024天 1024&#xff0c;程序员的记忆 1. 机缘 从学生到社会&#xff0c;都在需求一个记录笔记的软件&#xff0c;而作为程序员&#xff0c;CSDN可云同步又可直接在云平台上看到 选择了…

基于图像合成和注意力的深度神经网络从计算机断层扫描灌注图像中自动分割缺血性脑卒中病变

Automatic ischemic stroke lesion segmentation from computed tomography perfusion images by image synthesis and attention-based deep neural networks 基于图像合成和注意力的深度神经网络从计算机断层扫描灌注图像中自动分割缺血性脑卒中病变背景贡献实验Comparison o…

静态电压继电器 JY-11A 辅助电压110VDC 额定电压100VAC 安装方式 板前接线

JY-10系列集成电路电压继电器 JY-11A集成电路电压继电器 JY-12A集成电路电压继电器 JY-11C集成电路电压继电器 JY-11D集成电路电压继电器 JY-12B集成电路电压继电器 JY-12C集成电路电压继电器 JY-12D集成电路电压继电器 1概述 JY系列集成电路电压继电器用于发电机、变…

大漠插件7.2353

工具名称:大漠插件7.2353 更新时间2023-12-29更新内容/v7.23531. FindPicSim优化,防止有些时候会找不到图2. 增加接口TerminateProcessTree3. 解决AsmCall 模式6在部分WIN11下无法正常生效的BUG/ 工具简介:大漠 综合 插件 (dm.dll)采用vc6.0编写&#xff0c;识别速度超级快&…

免费分享一套微信小程序扫码点餐(订餐)系统(uni-app+SpringBoot后端+Vue管理端技术实现) ,帅呆了~~

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序扫码点餐(订餐)系统(uni-appSpringBoot后端Vue管理端技术实现) &#xff0c;分享下哈。 项目视频演示 【免费】微信小程序扫码点餐(订餐)系统(uni-appSpringBoot后端Vue管理端技术实现) Java毕…

java: 5-4 while循环 + do while循环

文章目录 1. while循环1.1 基本语法1.2 流程图1.3 上手练习1.4 细节1.5 练习题 2. do while 循环2.1 基本语法2.2 流程图2.3 上手练习2.4 细节2.5 练习题 【老韩b站视频笔记p126-p132】 1. while循环 1.1 基本语法 1.2 流程图 1.3 上手练习 输出 10 句 你好,韩顺平教育。 pu…

2023年全国职业院校技能大赛(高职组)“云计算应用”赛项赛卷①

2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷1 目录 需要竞赛软件包环境以及备赛资源可私信博主&#xff01;&#xff01;&#xff01; 2023年全国职业院校技能大赛&#xff08;高职组&#xff09; “云计算应用”赛项赛卷1 模块一 …

CANoe中的AutoSequence

简单介绍&#xff1a; AutoSequence是一种简单的&#xff0c;快速的类似脚本的一个可视化自动脚本插件。使用起来非常方便&#xff0c;甚至在很多时候能够代替一些简单的脚本。 1&#xff1a;Automation工程的创建 &#xff08;1.1&#xff09;打开Automation插件,双击这个插…

【LLM 论文阅读】NEFTU N E: LLM微调的免费午餐

指令微调的局限性 指令微调对于训练llm的能力至关重要&#xff0c;而模型的有用性在很大程度上取决于我们从小指令数据集中获得最大信息的能力。在本文中&#xff0c;我们提出在微调正向传递的过程中&#xff0c;在训练数据的嵌入向量中添加随机噪声&#xff0c;论文实验显示这…

开源C语言库Melon:Cron格式解析

本文介绍开源C语言库Melon的cron格式解析。 关于 Melon 库&#xff0c;这是一个开源的 C 语言库&#xff0c;它具有&#xff1a;开箱即用、无第三方依赖、安装部署简单、中英文文档齐全等优势。 Github repo 简介 cron也就是我们常说的Crontab中的时间格式&#xff0c;格式如…

2024年1月9日学习总结

目录 学习目标学习内容联邦学习基础&#xff1a;why, what, howwhy&#xff1f;what&#xff1f;how&#xff1f; 联邦学习的例子——CIFAR-10数据集&#xff08;分类问题&#xff09;1、import libararies2、hyper-parameters3、加载并且划分数据4、创建神经网络模型5、helper…

JMeter之Windows安装

JMeter之Windows安装 一、安装JDK二、安装JMeter1、下载JMeter2、配置环境变量3、验证JMeter 三、扩展知识1、汉化 一、安装JDK 略 二、安装JMeter 1、下载JMeter 官网地址&#xff1a;https://jmeter.apache.org/download_jmeter.cgi 放到本地目录下 2、配置环境变量 变量…

2024PMP考试新考纲-【过程领域】近期典型真题和超详细解析

前面的文章&#xff0c;华研荟讲解了三十多道PMP新考纲下的【人员People领域】的近年真题&#xff0c;这篇文章开始为大家分享【过程Process领域】的新考纲下的真题&#xff0c;进一步帮助大家体会和理解新考纲下PMP的考试特点和如何应用知识来解题&#xff0c;并且举一反三&am…

thinkphp学习06-连接数据库与模型初探

新建数据库 CREATE DATABASE tp6stu01 CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;创建表和数据 DROP TABLE IF EXISTS tp_user; CREATE TABLE tp_user (id mediumint(8) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 自动编号,username varchar(20) CHARACTER SET utf8 COLL…

Web APIs知识点讲解

学习目标: 能获取DOM元素并修改元素属性具备利用定时器间歇函数制作焦点图切换的能力 一.Web API 基本认知 1.作用和分类 作用: 就是使用 JS 去操作 html 和浏览器分类&#xff1a;DOM (文档对象模型)、BOM&#xff08;浏览器对象模型&#xff09; 2.DOM DOM(Document Ob…

SpringBoot-开启Admin监控服务

SpringBoot-Admin是一个用于管理和监控SpringBoot应用程序的开源项目。它提供了一个易于使用的Web界面&#xff0c;可以实时监控应用程序的健康状况、性能指标、日志和环境配置等信息。通过Actuator模块来收集和暴露应用程序的监控信息&#xff0c;使用Web Socket或者Server-Se…

C#PDF转Excel

組件 Spire.Pdf.dll, v7.8.9.0 【注意&#xff1a;版本太低的没有此功能】 在Visual Studio中找到参考&#xff0c;鼠标右键点击“引用”&#xff0c;“添加引用”&#xff0c;将本地路径debug文件夹下的dll文件添加引用至程序。 界面图&#xff1a; 1个label&#xff0c;1…