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

Java中的阻塞队列--以LinkedBlockingQueue为例

顾名思义,就是一种在对队列进行出队或者入队操作的时候会阻塞的队列。下面使用JDK17中的LinkedBlockingQuece进行简单的介绍。

LinkedBlockingQueue基本结构

LinkedBlockingQueue的主要结构以及构成的数据结构如下图所示。具体来说包括

  • 存储元素的链表,first指针指向队头,last指针指向队尾。
  • 控制向队列中入队节点的可重入锁 putLock,以及队列满时让生产者线程排队等待的 notFull 条件等待队列。
  • 控制向队列中出队节点的可重入锁 takeLock,以及队列为空的时候让消费者排队的 notEmpty 条件等待队列。
  • 尝试入队操作的生产者线程。
  • 尝试出队操作的消费者线程。

接下来介绍LinkedBlockingQueue的几个基本操作。

入队操作:

  • put(E) 将元素入队,如果队列满了那么将操作线程放入等待队列notFull, 直到入队成功。
  • offer(E) 将元素入队,如果队列满了那么直接返回false,入队失败。

出队操作:

  • take() 将元素出队,如果队列为空那么将操作线程放入等待队列notEmpty,直到出队成功。
  • poll() 将元素出队,如果队列为空返回false,出队失败。

put,offer以及 take,poll的操作之间的不同都是在队列不满足条件的时候是将其放入条件等待队列等待队列满足条件的时候唤醒还是直接返回false表示操作失败。

出队入队的基本操作

put(E e)

具体流程如下图所示,这是一个线程安全的队列,因为每次队队列的入队出队操作必须获取锁之后才会继续运行。生产者线程在获取了putLock后判断队列是否还会达到容量,如果还有容量那么直接放入,如果队列已满那么放入notFull等待队列中。因为生产者在队尾操作,消费者在队头操作,不会相互影响,在新增节点的过程中可能会有节点出队。所以在放入元素后判断队列是否还有容量,如果有就将notFull等待队列中的线程唤醒。在释放锁后判断在插入前队列是否为空,如果为空,说明可能有消费者线程在条件等待队列中等待获取元素,那么就去唤醒notEmpty中的线程,这些线程由于之前队列为空被放入条件等待队列等待。

public void put(E e) throws InterruptedException {if (e == null) throw new NullPointerException();final int c;final Node<E> node = new Node<E>(e);final ReentrantLock putLock = this.putLock;final AtomicInteger count = this.count;putLock.lockInterruptibly();try {/** Note that count is used in wait guard even though it is* not protected by lock. This works because count can* only decrease at this point (all other puts are shut* out by lock), and we (or some other waiting put) are* signalled if it ever changes from capacity. Similarly* for all other uses of count in other wait guards.*/while (count.get() == capacity) {notFull.await();}enqueue(node);c = count.getAndIncrement();if (c + 1 < capacity)notFull.signal();} finally {putLock.unlock();}if (c == 0)signalNotEmpty();
}

take()

take操作与put操作类似,只不过操作的锁和等待队列恰好相反。

public E take() throws InterruptedException {final E x;final int c;final AtomicInteger count = this.count;final ReentrantLock takeLock = this.takeLock;takeLock.lockInterruptibly();try {while (count.get() == 0) {notEmpty.await();}x = dequeue();c = count.getAndDecrement();if (c > 1)notEmpty.signal();} finally {takeLock.unlock();}if (c == capacity)signalNotFull();return x;}

另外需要注意的是 使用的两个可重入锁为 非公平锁,也就是说队列中的顺序并不严格满足先进先出的特性。源码的解释也有点冲突。

http://www.lryc.cn/news/524408.html

相关文章:

  • 16.5万煤气柜柜位计故障分析
  • 高效沟通驱动LabVIEW项目成功
  • 大模型之三十三- 开源Melo 语音合成
  • 论文复现:四轮转向车辆后轮转角控制方法研究
  • 【UFEN】基于多层特征融合和多任务学习的多模态情感分析
  • uniapp的插件开发发布指南
  • 【Linux系统】—— 编译器 gcc/g++ 的使用
  • [微服务]注册中心优化
  • C++ ——— 模拟实现 vector 类
  • 大华相机DH-IPC-HFW3237M支持的ONVIF协议
  • 【Java】常用工具类方法:树形结构、获取IP、对象拷贝、File相关、雪花算法等
  • 豆瓣电影Top250的数据采集与可视化分析(scrapy+mysql+matplotlib)
  • 2024微短剧行业生态洞察报告汇总PDF洞察(附原数据表)
  • PHP语言的数据库交互
  • flutter跨端UI框架简介
  • 自动化标注平台开源,基于 yolov8标注平台可本地部署
  • Walrus Learn to Earn计划正式启动!探索去中心化存储的无限可能
  • 第35天:安全开发-JavaEE应用原生反序列化重写方法链条分析触发类类加载
  • 【mptcp】ubuntu18.04和MT7981搭建mptcp测试环境操作说明
  • 【数据分析(二)】初探 Pandas
  • 第9章:Python TDD解决货币对象相等性比较难题
  • 更新布局元素的属性
  • UDP協議與代理IP介紹
  • QT 中 UDP 的使用
  • leetcode刷题记录(七十二)——146. LRU 缓存
  • 深圳大学-计算机系统(3)-实验一MIPS指令集实验
  • Java面试专题——面向对象
  • 知行合一:解决有心无力的问题,解决知易行难的问题,知行合一并不意味着事事都要合一,而是....
  • Qt中自定义信号与槽
  • .NET 8 项目 Docker 方式部署到 Linux 系统详细操作步骤