阻塞队列(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/网…

人工智能(AI)在未来娱乐行业的革命性影响

随着科技的飞速发展&#xff0c;人工智能&#xff08;AI&#xff09;已逐步渗透到各行各业&#xff0c;尤其在娱乐行业中的应用前景尤为广阔。本文将深入探讨AI对未来娱乐行业可能产生的深远影响。 首先&#xff0c;内容创作领域将迎来重大变革。AI技术可以辅助甚至独立完成剧本…

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

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

考勤信息(100用例)C卷 (JavaPythonC++Node.jsC语言)

公司用一个字符申来表示员工的出勤信息: absent:缺勒 late: 迟到 leaveearly:早退 present:正常上班 现需根据员工出勤信息,判断本次是否能获得出勤奖,能获得出勤奖的条件如下: 缺勤不超过一次:没有连续的迟到/早退:任意连续7次考勤。缺勤/迟到/早退不超过3次 输入描述: 用…

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

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毕…

npm install 报错 Error: EPERM: operation not permitted, rename

报错的解决方案 原因1&#xff1a; 权限不足原因2&#xff1a;缓存出错方法1方法2 原因3&#xff1a;npm版本不够原因4&#xff1a;网络不稳定方法1方法2 原因5&#xff1a; 杀毒软件问题方法1方法2 其他&#xff1a;待补充 原因1&#xff1a; 权限不足 用管理员身份打开终端再…

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;格式如…

三分钟学会cron 表达式

Cron 表达式 Cron 表达式是一种用于配置定时任务的时间表达式。它由六个字段组成&#xff0c;分别表示分钟、小时、日期、月份、星期和年份。 Cron 表达式的格式如下&#xff1a; * * * * * * | | | | | | | | | | | -- Year (optional) | | | | ---- Day of the Week (0-7,…

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、配置环境变量 变量…

算法复习笔记

这里写自定义目录标题 C/C快速入门头文件主函数输入输出函数变量类型注意if语句switch语句循环结构while语句do...while语句for语句break和continue语句 数组注意 string.h头文件指针引用浮点数的比较 C/C快速入门 头文件 通过#include<x.h>写法来写&#xff0c;例如: …