当前位置: 首页 > ops >正文

Java基于数组的阻塞队列实现详解

在多线程编程中,阻塞队列是一种非常有用的工具,它可以在生产者和消费者之间提供一个缓冲区,使得生产者可以往队列中添加数据,而消费者可以从队列中取出数据。当队列满时,生产者会被阻塞直到有空间可用;当队列空时,消费者会被阻塞直到有数据可用。本文将详细分析一个基于数组实现的阻塞队列代码。

代码结构概述

我们先来浏览一下整个代码的结构:

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;public class ArrBlockQueue<E> {// 成员变量private Object[] arr;private int size = 0;private int head = 0;  // 存数据位置private int last = 0;  // 取数位置private ReentrantLock lock = new ReentrantLock();private Condition notEmpty = lock.newCondition();private Condition notFull = lock.newCondition();// 构造函数public ArrBlockQueue(int len) {arr = new Object[len];}// 添加数据方法public void put(E e) throws InterruptedException {lock.lock();try {while (size == arr.length) {notFull.await();}System.out.println("put 添加数据 " + e);arr[head] = e;head = (head + 1) % arr.length;size++;notEmpty.signal();} finally {lock.unlock();}}// 取出数据方法(未完成)public E take() throws InterruptedException {}// 获取队列大小方法public int size() {lock.lock();try {return size;} finally {lock.unlock();}}// 主方法(测试用)public static void main(String[] args) {// 测试代码}
}

关键组件解析

1. 同步控制部分

private ReentrantLock lock = new ReentrantLock();
private Condition notEmpty = lock.newCondition();
private Condition notFull = lock.newCondition();

这里使用了ReentrantLockCondition来实现同步控制:

  • ReentrantLock:这是一个可重入的互斥锁,它可以替代synchronized关键字提供更灵活的锁定机制。在这里,它用于确保对共享资源的独占访问。

  • Condition:这是ReentrantLock的一个条件变量接口,用于实现复杂的等待/通知机制。在这里,我们创建了两个条件变量:

    • notEmpty:用于通知消费者队列已非空,可以取数据了。
    • notFull:用于通知生产者队列已非满,可以添加数据了。

2. 数据存储部分

private Object[] arr;
private int size = 0;
private int head = 0;  // 存数据位置
private int last = 0;  // 取数位置

这是阻塞队列的核心数据结构:

  • arr:一个对象数组,用于存储队列中的元素。
  • size:当前队列中的元素数量。
  • head:指向队列头部(下一个要添加元素的位置)。
  • last:指向队列尾部(下一个要取出元素的位置)。

3. 添加数据方法

public void put(E e) throws InterruptedException {lock.lock();try {while (size == arr.length) {notFull.await();}System.out.println("put 添加数据 " + e);arr[head] = e;head = (head + 1) % arr.length;size++;notEmpty.signal();} finally {lock.unlock();}
}

这是生产者线程调用的方法:

  • lock.lock():获取锁,确保线程安全。

  • while (size == arr.length):检查队列是否已满。如果队列满了,调用notFull.await()使当前线程进入等待状态,直到队列有空间可用。

  • 添加数据到arr数组的head位置,更新head指针,并增加size计数。

  • notEmpty.signal():通知可能正在等待队列非空的消费者线程,队列已经可以取出数据了。

  • lock.unlock():释放锁。

代码运行示例

main方法中,创建了一个长度为5的阻塞队列实例:

ArrBlockQueue<Integer> block = new ArrBlockQueue<>(5);

启动两个线程:

  1. 一个生产者线程,循环添加10个元素到队列中:
new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ": put 线程启动!");for (int i = 0; i < 10; i++) {try {block.put(i);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}).start();
  1. 一个消费者线程,循环从队列中取出10个元素:
new Thread(new Runnable() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + ": take 线程启动!");for (int i = 0; i < 10; i++) {try {Thread.sleep(500);System.out.println(block.take());} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}).start();

总结

这个基于数组的阻塞队列实现展示了如何使用ReentrantLockCondition来实现复杂的等待/通知机制。它为生产者和消费者模式提供了一个线程安全的解决方案,确保了数据的一致性和线程间的高效协作。理解这种实现方式有助于我们更好地掌握Java并发编程的核心概念。

http://www.xdnf.cn/news/7059.html

相关文章:

  • Qt音视频开发过程中一个疑难杂症的解决方法/ffmpeg中采集本地音频设备无法触发超时回调
  • 健康生活:养生实用指南
  • 浅谈无服务器WebSocket的优势
  • 什么是open BMC?
  • Spring AI Alibaba集成阿里云百炼大模型
  • 异常日志规范
  • 低功耗模式介绍
  • Java配置文件处理工具全解析
  • 人工智能赋能产业升级:AI在智能制造、智慧城市等领域的应用实践
  • 何首乌基因组-文献精读131
  • 代码上传gitte仓库
  • 【C语言练习】048. 使用递归进行树的遍历
  • 【软考 8T(n / 2)+n^2的时间复杂度如何计算?】
  • C++(21):fstream的读取和写入
  • DeepSeek系列核心技术与贡献总结
  • 生产级编排AI工作流套件:Flyte全面使用指南 — Data input/output
  • 互联网大厂Java面试:从基础到复杂场景的技术挑战
  • 二:操作系统之进程概念
  • Unity学习总结篇(1)关于各种坐标系
  • 信息学奥赛一本通1012:计算多项式的值
  • Spring-Beans的生命周期的介绍
  • python3.13版本降为3.12
  • 基于STM32F103与Marvell88W8686的WIFI无线监控视频传输系统研发(论文)
  • 生成树的保护机制
  • 【运营商查询】批量手机号码归属地和手机运营商高速查询分类,按省份城市,按运营商移动联通电信快速分类导出Excel表格,基于WPF的实现方案
  • 院校机试刷题第六天:1134矩阵翻转、1052学生成绩管理、1409对称矩阵
  • AI驱动的研发流程:定义高度专业和系统化的规划基准
  • 软件架构设计--期末复习
  • 5月18总结
  • 拓展运算符