Java并发基础:ArrayBlockingQueue全面解析!

Java并发基础:ArrayBlockingQueue全面解析! - 程序员古德

内容摘要

ArrayBlockingQueue类是一个高效、线程安全的队列实现,它基于数组,提供了快速的元素访问,并支持多线程间的同步操作,作为有界队列,它能有效防止内存溢出,并通过阻塞机制平衡生产者和消费者的速度差异,它还提供了公平性和非公平性策略,满足不同场景下的需求。

核心概念

主要场景

在现实业务场景中,可以将ArrayBlockingQueue地运用到许多需要处理并发和资源限制的问题上,假设,团队正在构建一个在线订餐系统,其中有一个核心模块负责处理订单请求并将订单分配给餐厅厨房进行制作。

比如,厨房的每个工作台都有一定的处理能力,比如同时只能处理5个订单,超过这个数量,工作台就会变得拥挤而无法再接单,为了模拟这种有限的处理能力,可以创建一个容量为5的ArrayBlockingQueue

每当用户通过前端提交了一个新的订单请求时,后端的订单处理器线程会尝试将这个订单对象作为一个任务放入ArrayBlockingQueue中,如果此时队列未满,订单会被成功放入并通知厨房开始处理;但如果队列已满,则表示当前厨房工作台负荷过大,订单处理器线程会进入等待状态,直到厨房完成了一个订单并将结果从队列中取出后,新订单才有机会被加入队列。

此刻,ArrayBlockingQueue就像是厨房与订单处理器之间的缓冲区和信号灯,它既能控制流入厨房的订单流,防止过载,又能确保订单处理器在没有订单可处理时不会空转浪费资源,从而保证整个系统的稳定性和效率。

主要功能

ArrayBlockingQueue主要用于解决以下功能问题:

  1. 多线程间的数据共享
    在多线程编程中,线程之间经常需要共享数据ArrayBlockingQueue作为一个线程安全的队列,允许不同线程安全地添加和移除元素,它内部的同步机制确保了在并发环境下数据的一致性和完整性。
  2. 生产者-消费者协作
    ArrayBlockingQueue是实现生产者-消费者模式的理想选择,在生产者-消费者模式中,生产者产生数据放入缓冲区,而消费者从缓冲区中取走数据,ArrayBlockingQueue的阻塞特性能够自动调节生产者和消费者的速度:当缓冲区满时,生产者会被阻塞直到有空间可用;当缓冲区空时,消费者会被阻塞直到有数据可取。
  3. 流量控制
    由于ArrayBlockingQueue是一个有界队列,它可以用来实现流量控制,通过设置队列的最大容量,可以限制系统中待处理的任务或数据的数量,这对于防止资源过载和维持系统的稳定性至关重要。
  4. 任务调度与负载均衡
    在并发系统中,ArrayBlockingQueue可以作为任务队列使用,用于存储待执行的任务,线程池中的工作线程可以从队列中取出任务进行处理,从而实现任务的调度和负载均衡。
  5. 解耦
    使用ArrayBlockingQueue可以将数据的生产和消费解耦,生产者不需要知道消费者的具体实现,只需要将数据放入队列;同样,消费者也不需要知道生产者的具体实现,只需要从队列中取出数据,这提高了系统的可维护性和可扩展性。
  6. 缓冲
    ArrayBlockingQueue作为一个缓冲区,可以平滑生产者和消费者之间的速度差异,当生产者速度较快时,队列可以存储多余的数据;当消费者速度较快时,队列可以提供足够的数据供其消费,这有助于减少系统的响应时间和提高吞吐量。

代码案例

下面是一个简单的Java程序,演示了如何使用ArrayBlockingQueue类实现一个生产者-消费者场景,其中生产者线程向队列中添加数据,而消费者线程从队列中移除数据,如下代码:

import java.util.concurrent.ArrayBlockingQueue;  
import java.util.concurrent.BlockingQueue;  // 生产者类,用于向队列中添加数据  
class Producer implements Runnable {  private final BlockingQueue<Integer> queue;  private final int maxSize;  public Producer(BlockingQueue<Integer> queue, int maxSize) {  this.queue = queue;  this.maxSize = maxSize;  }  @Override  public void run() {  try {  for (int i = 0; i < maxSize; i++) {  // 模拟生产时间  Thread.sleep((long) (Math.random() * 1000));  queue.put(i); // 将数据放入队列,如果队列已满则阻塞  System.out.println("Produced: " + i);  }  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  
}  // 消费者类,用于从队列中移除数据  
class Consumer implements Runnable {  private final BlockingQueue<Integer> queue;  public Consumer(BlockingQueue<Integer> queue) {  this.queue = queue;  }  @Override  public void run() {  try {  while (true) {  Integer consumed = queue.take(); // 从队列中取出数据,如果队列为空则阻塞  System.out.println("Consumed: " + consumed);  // 假设消费完maxSize-1个元素后,消费者就不再消费了  if (consumed == queue.remainingCapacity()) {  break;  }  // 模拟消费时间  Thread.sleep((long) (Math.random() * 1000));  }  } catch (InterruptedException e) {  Thread.currentThread().interrupt();  }  }  
}  // 主类,包含main方法,用于启动生产者和消费者线程  
public class ArrayBlockingQueueDemo {  public static void main(String[] args) {  int queueSize = 5; // 队列大小  BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(queueSize); // 创建一个有界阻塞队列  // 启动生产者线程  Thread producerThread = new Thread(new Producer(queue, queueSize));  producerThread.start();  // 启动消费者线程  Thread consumerThread = new Thread(new Consumer(queue));  consumerThread.start();  }  
}

在这个例子中,创建了一个大小为5的ArrayBlockingQueue,生产者线程会生成从0到4的整数,并尝试将它们放入队列中,如果队列已满,生产者线程会阻塞,直到队列中有空间可用,消费者线程会不断尝试从队列中取出元素,如果队列为空,消费者线程会阻塞,直到队列中有元素可取,生产者和消费者线程都使用了Thread.sleep()方法来模拟生产和消费的时间延迟。

Produced: 0  
Produced: 1  
Consumed: 0  
Produced: 2  
Consumed: 1  
Produced: 3  
Consumed: 2  
Produced: 4  
Consumed: 3  
Consumed: 4

核心API

ArrayBlockingQueue实现了一个基于数组的有界阻塞队列,这个队列按照 FIFO(先进先出)的原则对元素进行排序,当尝试向已满的队列中放入元素时,操作将会被阻塞;当尝试从空队列中取出元素时,操作也会被阻塞,以下是ArrayBlockingQueue类中一些主要方法的含义:

1、核心构造方法

  1. ArrayBlockingQueue(int capacity): 创建一个具有给定容量的新的ArrayBlockingQueue实例。
  2. ArrayBlockingQueue(int capacity, boolean fair): 创建一个具有给定容量和公平性设置的新ArrayBlockingQueue实例,如果设置为公平,等待时间最长的线程将获得访问队列的优先权;如果设置为不公平,则访问顺序是不确定的。

2、添加元素

  1. add(E e): 将指定的元素插入此队列的尾部,如果队列已满,则抛出IllegalStateException
  2. offer(E e): 将指定的元素插入此队列的尾部,如果队列已满,则返回false
  3. put(E e) throws InterruptedException: 将指定的元素插入此队列的尾部,等待必要的空间变得可用,如果当前线程被中断,则抛出InterruptedException
  4. offer(E e, long timeout, TimeUnit unit): 将指定的元素插入此队列的尾部,等待指定的时间以使空间变得可用,如果在指定的时间内队列仍然满,则返回false

3、移除元素

  1. remove(): 移除并返回此队列的头部,如果队列为空,则抛出NoSuchElementException
  2. poll(): 移除并返回此队列的头部,或者如果队列为空,则返回null
  3. take() throws InterruptedException: 移除并返回此队列的头部,等待元素变得可用,如果当前线程被中断,则抛出InterruptedException
  4. poll(long timeout, TimeUnit unit): 移除并返回此队列的头部,等待指定的时间以使元素可用,如果在指定的时间内队列仍然为空,则返回null

4、检查元素

  1. element(): 获取但不移除此队列的头部,如果队列为空,则抛出NoSuchElementException
  2. peek(): 获取但不移除此队列的头部,或者如果队列为空,则返回null

5、其他方法

  1. size(): 返回队列中的元素数量。
  2. remainingCapacity(): 返回队列的理想最大容量与当前大小之间的差值。
  3. clear(): 移除此队列中的所有元素。
  4. contains(Object o): 如果此队列包含指定的元素,则返回true
  5. drainTo(Collection<? super E> c): 移除此队列中所有可用的元素,并将它们添加到给定的集合中。
  6. drainTo(Collection<? super E> c, int maxElements): 最多从此队列中移除给定数量的可用元素,并将这些元素添加到给定的集合中。
  7. toArray(): 返回以适当顺序包含此队列中所有元素的数组。
  8. iterator(): 返回在此队列的元素上进行迭代的迭代器。

核心总结

Java并发基础:ArrayBlockingQueue全面解析! - 程序员古德

ArrayBlockingQueue是一个非常实用的有界阻塞队列,其优点在于,基于数组实现,内存占用连续,查询速度快;同时支持多线程间的同步操作,能够很好地处理生产者-消费者问题。

另外,它还可以设置公平性,确保等待时间最长的线程优先获取资源。但是,由于是基于数组实现的,所以在初始化时需要指定队列大小,且之后无法改变,这在某些场景下可能不够灵活,当队列满或空时,相关操作会被阻塞,如果处理不当,可能会导致线程挂起或资源浪费。

在使用ArrayBlockingQueue时,要合理设置队列大小,避免过大或过小,同时,要注意处理阻塞情况,可以通过设置超时时间或使用offerpoll等非阻塞方法来避免线程长时间等待,此外,在多线程环境下使用时,要注意线程安全问题,确保数据的正确性和一致性。

关注我,每天学习互联网编程技术 - 程序员古德

END!

往期回顾

Java并发基础:LinkedTransferQueue全面解析!

Java并发基础:BlockingQueue和BlockingDeque接口的区别?

Java并发基础:Deque接口和Queue接口的区别?

Spring核心基础:全面总结Spring中提供的那些基础工具类!

Java并发基础:FutureTask全面解析!

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

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

[职场] 公安管理学就业方向及前景 #媒体#笔记#笔记

公安管理学就业方向及前景 公安管理学是中国普通高等学校本科专业。本专业文理兼收&#xff0c;学制4年&#xff0c;授予法学学士学位。本专业培养掌握马克思主义基本原理&#xff0c;政治坚定&#xff0c;坚持党和国家的路线、方针、政策&#xff0c;具有良好职业素养、科学素…

K210如何下载程序

一、打开资料包里提供的K-Flash程序烧录软件 二、选择串口 三、选择波特率 四、选择In-Chip&#xff0c;烧录到Flash芯片里面&#xff0c;重新上电还会运行程序 五、如果选择In - Memory&#xff0c;这次可以运行&#xff0c;但下次重新上电就不会保持这次的程序了。 六、选择固…

macOS Sonoma 14.3.1(23D60)发布

系统介绍 黑果魏叔2 月 9 日消息&#xff0c;苹果今日向 Mac 电脑用户推送了 macOS 14.3.1 更新&#xff08;内部版本号&#xff1a;23D60&#xff09;&#xff0c;本次更新距离上次发布隔了 17 天。 魏叔 查询苹果官方更新日志&#xff0c;macOS Sonoma 14.3.1 修复内容和 …

LeetCode-第28题-找出字符串中第一个匹配项的下标

1.题目描述 给你两个字符串 haystack 和 needle &#xff0c;请你在 haystack 字符串中找出 needle 字符串的第一个匹配项的下标&#xff08;下标从 0 开始&#xff09;。如果 needle 不是 haystack 的一部分&#xff0c;则返回 -1 。 2.样例描述 3.思路描述 可以让字符串 …

【JAVA WEB】盒模型

目录 边框 内边距 基础写法 复合写法 外边距 基础写法 复合写法 块级元素的水平居中 弹性布局 设置行内元素的属性 &#xff0c;span 每一个HTML元素就相当于是一个矩形的“盒子” 这个盒子由以下这几个部分构成&#xff1a; 1.边框 border 2.内容 content 3.内边…

写后台接口,前后台数据对接(vue+springboot)

一、怎么写接口&#xff1f;&#xff1f;&#xff1f; 1.Entity&#xff08;定义一堆属性之类的&#xff09; altins>getter和setter方法 2.Controller 3.Service&#xff08;查询出数据&#xff09; 调用了一个方法 4.Mapper 5.回到service&#xff08;返回数据&#x…

2019 年全国职业院校技能大赛高职组 “信息安全管理与评估”赛项任务书(笔记详解)

1. 网络拓扑图 2. IP 地址规划表 3. 设备初始化信息 阶段一 任务 1:网络平台搭建 1、根据网络拓扑图所示,按照 IP 地址参数表,对 DCFW 的名称、各接口IP 地址进行配置。 2、根据网络拓扑图所示,按照 IP 地址参数表,对 DCRS 的名称进行配置,创建 VLAN 并将相应接口划入 …

ChatGPT高效提问—prompt常见用法(续篇七)

ChatGPT高效提问—prompt常见用法&#xff08;续篇七&#xff09; 1.1 零样本、单样本和多样本 ​ ChatGPT拥有令人惊叹的功能和能力&#xff0c;允许用户自由向其提问&#xff0c;无须提供任何具体的示例样本&#xff0c;就可以获得精准的回答。这种特性被称为零样本&#x…

【教3妹学编程-算法题】LCP 30. 魔塔游戏

3妹&#xff1a;2哥&#xff0c;干嘛呢&#xff0c;一个人闷闷不乐的&#xff0c;在看什么呢。 2哥 : 这不快过年了嘛&#xff0c; 想回家过年给我的小侄子买个礼物&#xff0c;结果他张口说想要个ps5. 那玩意我都没有&#xff0c;他还想要。我看看网上有什么好的礼物适合他的。…

vscode开发FPGA(0)--windows平台搭建

一、从官网下载安装VScode Download Visual Studio Code - Mac, Linux, Windows 二、安装配置插件 1. 安装Chinese&#xff08;simplified&#xff09;中文汉化包 2.安装Verilog-HDL/systemVerilog插件(支持verilog语法) 3.配置CTags Support插件(支持代码跳转) 1)在github下…

鸿蒙(HarmonyOS)项目方舟框架(ArkUI)之Slider组件

鸿蒙&#xff08;HarmonyOS&#xff09;项目方舟框架&#xff08;ArkUI&#xff09;之Slider组件 一、操作环境 操作系统: Windows 10 专业版、IDE:DevEco Studio 3.1、SDK:HarmonyOS 3.1 二、Slider组件 滑动条组件&#xff0c;通常用于快速调节设置值&#xff0c;如音量调…

AcWing 1224 交换瓶子(简单图论)

[题目概述] 有 N 个瓶子&#xff0c;编号 1∼N&#xff0c;放在架子上。 比如有 5 个瓶子&#xff1a; 2 1 3 5 4 要求每次拿起 2 个瓶子&#xff0c;交换它们的位置。 经过若干次后&#xff0c;使得瓶子的序号为&#xff1a; 1 2 3 4 5 对于这么简单的情况&#xff0c;显然&a…

[SAP] ABAP代码程序美化器大小写格式化设置

按照ABAP开发的规范&#xff0c;ABAP源代码里推荐将所有的关键字大写&#xff0c;其余ABAP变量小写 我们可以手动修改上述代码大小写规范的问题&#xff0c;但如果代码量很多的情况下&#xff0c;手动确保这个规范(所有的关键字大写&#xff0c;其余ABAP变量小写)有点费事&…

LabVIEW工业监控系统

LabVIEW工业监控系统 介绍了一个基于LabVIEW软件开发的工业监控系统。系统通过虚拟测控技术和先进的数据处理能力&#xff0c;实现对工业过程的高效监控&#xff0c;提升系统的自动化和智能化水平&#xff0c;从而满足现代工业对高效率、高稳定性和低成本的需求。 随着工业自…

TP-LINK今年的年终奖。。

TP-LINK 年终奖 如果说昨天爆料的「浦发银行年终奖&#xff0c;一书抵万金」还稍有争议&#xff08;有些说没发&#xff0c;有些说 3/4/5 折&#xff09;&#xff0c;那今天的 TP-LINK 则是毫无悬念。 据在职的 TP-LINK 技术员工爆料&#xff1a;入职时说好的 16 薪&#xff0c…

Blazor Wasm Gitee 码云登录

目录: OpenID 与 OAuth2 基础知识Blazor wasm Google 登录Blazor wasm Gitee 码云登录Blazor SSR/WASM IDS/OIDC 单点登录授权实例1-建立和配置IDS身份验证服务Blazor SSR/WASM IDS/OIDC 单点登录授权实例2-登录信息组件wasmBlazor SSR/WASM IDS/OIDC 单点登录授权实例3-服务端…

联合体知识点解析

联合体&#xff1a; 联合体也是一种自定义类型&#xff0c; 特点是成员变量公用一块空间。所以也叫共用体。 联合体的性质 先定义一个联合体&#xff1a; 然后我创建一个联合体变量&#xff1a; 现在探究当修改一个成员变量的值时&#xff0c; 其他成员变量的值能否被修改&am…

Python相关的基础模块

Python相关的基础模块 在编写远程控制工具之前&#xff0c;先要介绍用Python编写远程控制工具时所需要的 相关模块&#xff0c;为接下来编写工具打下基础。 1.subprocess模块 subprocess模块的主要作用是执行外部的命令和程序。当我们运行Python的时 候&#xff0c;其实也是在运…

endnotesX9 如何批量导入 .enw文件

文章是用schoolar搜出来 点击下载引用之后&#xff0c;endnotesX9只能一个一个从.enw文件导入&#xff0c;麻烦 —————————————— 可以在schoolar保存到个人图书馆 类似于上面这种&#xff0c;我用的是保存&#xff0c;保存很多的论文之后点我的个人图书馆&#x…

网友:感谢华为救了我的下半生。

(关注数据结构和算法&#xff0c;了解更多新知识) 最近一位网友发视频称&#xff0c;华为Mate60 Pro帮他挡了子弹。视频配文&#xff1a;“一场意外&#xff0c;没有这个手机隔挡&#xff0c;下半生我可能就在轮椅上度过了&#xff01;”视频中&#xff0c;手机摄像头右侧被击中…