34.Java 阻塞队列(阻塞队列架构、阻塞队列分类、阻塞队列核心方法)

news/2025/2/26 6:29:36

一、阻塞队列概述

  • java.util.concurrent 包下的 BlockingQueue 接口很好的解决了多线程中如何高效安全传输数据的问题,可以使用这些高效并且线程安全的队列类快速搭建高质量的多线程程序

  • 阻塞队列通过一个共享的队列,使得数据由队列的一端输入,从另外一端输出,当队列空时,从队列中获取元素的操作将会被阻塞,当队列满时,从队列中添加元素的操作将会被阻塞

  • 试图从空的队列中获取元素的线程将会被阻塞,直到其他线程往空的队列插入新的元素,试图向已满的队列中添加新元素的线程将会被阻塞,直到其他线程从队列中移除一个或多个元素或者完全清空

  • 所谓阻塞,即在某些情况下将线程挂起,一旦条件满足,被挂起的线程会自动被唤起

  • 多线程环境中,通过队列可以很容易实现数据共享,比如经典的生产者和消费者模型,通过队列可以很便利地实现两者之间的数据共享

  • 当队列中没有数据时,消费者端的所有线程都会被阻塞,直到有数据存入队列,当队列中填满数据的情况下,生产者端的所有线程都会被阻塞,直到队列中有空间


二、阻塞队列架构

  • BlockingQueue 接口的超接口有 Collection、Iterable、Queue

  • BlockingQueue 接口的实现类有 ArrayBlockingQueue、DelayQueue、LinkedBlockingDeque、LinkedBlockingQueue、LinkedTransferQueue、PriorityBlockingQueue、SynchronousQueue


三、阻塞队列分类

1、ArrayBlockingQueue 类
  • ArrayBlockingQueue 是由数组结构实现的有界阻塞队列

  • ArrayBlockingQueue 在生产者存放数据和消费者获取数据时都是共用同一个锁对象,无法并行

2、LinkedBlockingQueue 类
  • LinkedBlockingQueue 是由链表结构实现的有界阻塞队列,大小默认值为 Integer.MAX_VALUE

  • LinkedBlockingQueue 对于生产者端和消费者端分别采用了独立的锁来控制数据同步,在高并发的情况下生产者和消费者可以并行地操作队列中的数据,以此来提高整个队列的并发性能

3、DelayQueue 类
  • 基于优先级队列实现的延迟无界阻塞队列

  • DelayQueue 中的数据只有当其达到指定的延迟时间,才能够从队列中获取到该数据

  • DelayQueue 是一个没有大小限制的队列,因此往队列中插入数据的操作(生产者)不会被阻塞,只有获取数据的操作(消费者)才会被阻塞

4、PriorityBlockingQueue 类
  • PriorityBlockingQueue 是基于优先级排序实现的无界阻塞队列

  • PriorityBlockingQueue 不会阻塞数据生产者,只会在没有可消费的数据时,阻塞数据的消费者

5、SynchronousQueue 类
  • SynchronousQueue 是无缓冲的等待队列

  • 相对于有缓冲的 BlockingQueue 来说,SynchronousQueue 少了一个中间经销商的环节(缓冲区)

  • SynchronousQueue 是不存储元素的阻塞队列,也即单个元素的队列

  • 声明一个 SynchronousQueue 对象有公平模式和非公平模式两种方式

(1)公平模式
  • SynchronousQueue 使用公平锁,并配合一个先进先出(FIFO)队列来阻塞多余的生产者和消费者,从而体系整体的公平策略
(2)非公平模式
  • SynchronousQueue 使用非公平锁,同时配合一个后进先出(LIFO)队列来管理多余的生产者和消费者

  • 这种模式,如果生产者和消费者的数据处理速度有差距,则很容易出现线程饥饿饥饿的情况,即可能有某些生产者或者是消费者的数据永远都得不到处理

6、LinkedTransferQueue 类
  • LinkedTransferQueue 是基于链表结构实现的无界阻塞队列

  • LinkedTransferQueue 采用一种预占模式,当消费者线程取数据时,如果队列不为空,则直接取走数据,若队列为空,那就生成一个节点数据为 null 的节点入队,然后消费者线程在该节点上等待,之后生产者线程入队时发现有一个节点数据为 null 的节点,生产者线程就不入对了,直接将数据填充到该节点,并唤醒该节点等待的消费者线程,被唤醒的消费者线程取走数据,从调用的方法返回

7、LinkedBlockingDeque 类
  • LinkedBlockingDeque 是基于链表结构组成的双向阻塞队列

  • LinkedBlockingDeque 有两种阻塞情况

(1)插入数据时阻塞
  • 当队列满时会进入阻塞状态,直到队列有空的位置时才可插入数据

  • 插入数据的操作可以通过设置超时时间,超时后返回 false 表示操作失败,也可以不设置超时时间,但是会被一直阻塞,被中断后会抛出 InterruptedException 异常

(2)读取数据时阻塞
  • 当队列空时会进入阻塞状态,直到队列不为空才可读取数据

  • 读取数据的操作同样可以设置超时时间


四、阻塞队列核心方法

  • BlockingQueue 的核心方法可以根据队列已满或为空时的执行情况分为抛出异常组、返回特殊值组、阻塞组、超时组
1、抛出异常组
(1)基本介绍
方法说明
boolean add(Object o)插入数据,成功时返回 true,当队列已满时再插入会抛出 java.lang.IllegalStateException 异常
Object remove()读取数据,成功时返回数据,当队列为空时再读取会抛出 java.util.NoSuchElementException 异常
Object element()检查数据,成功时返回数据,当队列为空时再读取会抛出 java.util.NoSuchElementException 异常
(2)演示
  • add 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.add(1)); // true
System.out.println(blockingQueue.add(2)); // true
System.out.println(blockingQueue.add(3)); // true
System.out.println(blockingQueue.add(4)); // 抛出 java.lang.IllegalStateException 异常
  • remove 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.add(1)); // true
System.out.println(blockingQueue.add(2)); // true
System.out.println(blockingQueue.add(3)); // true

System.out.println(blockingQueue.remove()); // 1
System.out.println(blockingQueue.remove()); // 2
System.out.println(blockingQueue.remove()); // 3
System.out.println(blockingQueue.remove()); // 抛出 java.util.NoSuchElementException 异常
  • element 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.add(1)); // true
System.out.println(blockingQueue.add(2)); // true
System.out.println(blockingQueue.add(3)); // true

System.out.println(blockingQueue.remove()); // 1
System.out.println(blockingQueue.element()); // 2

System.out.println(blockingQueue.remove()); // 2
System.out.println(blockingQueue.element()); // 3

System.out.println(blockingQueue.element()); // 抛出 java.util.NoSuchElementException 异常
2、返回特殊值组
(1)基本介绍
方法说明
boolean offer(Object o)插入数据,成功时返回 true,当队列已满时再插入返回 false
Object poll()读取数据,成功时返回数据,当队列为空时再读取返回 null
Object peek()检查数据,成功时返回数据,当队列为空时再读取返回 null
(2)演示
  • offer 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.offer(1)); // true
System.out.println(blockingQueue.offer(2)); // true
System.out.println(blockingQueue.offer(3)); // true
System.out.println(blockingQueue.offer(4)); // false
  • poll 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.offer(1)); // true
System.out.println(blockingQueue.offer(2)); // true
System.out.println(blockingQueue.offer(3)); // true

System.out.println(blockingQueue.poll()); // 1
System.out.println(blockingQueue.poll()); // 2
System.out.println(blockingQueue.poll()); // 3
System.out.println(blockingQueue.poll()); // null
  • peek 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.offer(1)); // true
System.out.println(blockingQueue.offer(2)); // true
System.out.println(blockingQueue.offer(3)); // true

System.out.println(blockingQueue.poll()); // 1
System.out.println(blockingQueue.peek()); // 2

System.out.println(blockingQueue.poll()); // 2
System.out.println(blockingQueue.peek()); // 3

System.out.println(blockingQueue.poll()); // 3
System.out.println(blockingQueue.peek()); // null

3、阻塞组
(1)基本介绍
方法说明
void put(Object o)插入数据,当队列已满时再插入会阻塞
Object take()读取数据,当队列为空时再读取会阻塞
(2)演示
  • put 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

blockingQueue.put(1);
System.out.println("a"); // a
        
blockingQueue.put(2);
System.out.println("b"); // b
        
blockingQueue.put(3);
System.out.println("c"); // c
        
blockingQueue.put(4); // 阻塞
System.out.println("d"); // 阻塞
  • take 方法
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

blockingQueue.put(1);
blockingQueue.put(2);
blockingQueue.put(3);

System.out.println(blockingQueue.take()); // 1
System.out.println(blockingQueue.take()); // 2
System.out.println(blockingQueue.take()); // 3
System.out.println(blockingQueue.take()); // 阻塞
4、超时组
(1)基本介绍
方法说明
boolean offer(Object o, long timeout, TimeUnit unit)插入数据,成功时返回 true,当队列已满时再插入会进入超时等待
超时等待后,能成功插入数据则返回 true,失败则返回 false
Object poll(long timeout, TimeUnit unit)读取数据,成功时返回数据,当队列为空时再读取会进入超时等待
超时等待后,能成功读取数据则返回数据,失败则返回 null
(2)演示
  • offer 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.offer(1, 3L, TimeUnit.SECONDS)); // true
System.out.println(blockingQueue.offer(2, 3L, TimeUnit.SECONDS)); // true
System.out.println(blockingQueue.offer(3, 3L, TimeUnit.SECONDS)); // true
System.out.println(blockingQueue.offer(4, 3L, TimeUnit.SECONDS)); // 超时等待,超时等待后返回 false
  • poll 方法演示
java">BlockingQueue blockingQueue = new ArrayBlockingQueue(3);

System.out.println(blockingQueue.offer(1, 3L, TimeUnit.SECONDS)); // true
System.out.println(blockingQueue.offer(2, 3L, TimeUnit.SECONDS)); // true
System.out.println(blockingQueue.offer(3, 3L, TimeUnit.SECONDS)); // true

System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS)); // 1
System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS)); // 2
System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS)); // 3
System.out.println(blockingQueue.poll(3L, TimeUnit.SECONDS)); // 超时等待,超时等待后返回 false

http://www.niftyadmin.cn/n/5868207.html

相关文章

OpenCvSharp编译

前言 算法部分我们使用opencv4.10作为开发,那么我们在.net winform做UI界面开发时,需要进行相关调用。比较简单的方式是直接从NuGet中直接搜索OpencvSharp进行安装。OpecvSharp对Opencv进行了二次封装,在.net中可以快速操作相关对象和算子&am…

网络安全学习-WEB安全常见漏洞

注入类漏洞 SQL注入漏洞 定义 sql注入漏洞,就是将用户可控的数据拼接到了sql语句当中,一起提交到了数据库执行。 攻*击者通过注入语句,改变sql执行的逻辑,通过控制部分sql语句,攻击者可以查询到数据库钟任何自己需…

【Uniapp-Vue3】导入uni-id用户体系

在uniapp官网的uniCloud中下载uni-id用户体系 或者直接进入加载,下载地址:uni-id-pages - DCloud 插件市场 进入以后下载插件,打开HbuilderX 选中项目,点击确定 点击跳过 点击合并 右键uniCloud文件夹下的database文件夹&#x…

React进阶之React核心源码解析(三)

React核心源码解析 diff多节点比较diff两轮遍历比较第一轮比较第二轮比较Update 状态更新Concurrent Modediff 多节点比较diff isArray方法比较 节点更新// 更新前 <ul><li key="0" className="before">0<li><li key=

【二值图像与手动/自动阈值的详解】

二值图像与手动/自动阈值的详解 目录 二值图像与手动/自动阈值的详解一. 什么是二值图像&#xff1f;二. 二值图像的特点三. 二值图像的生成四.二值图像中的阈值作用及使用方法1. 阈值的概念2. 阈值的作用3. 阈值的类型4. 阈值的选择方法4. 阈值的使用方法5. 阈值的选择对结果的…

在股市交易的强化学习中寻找最佳交易历史

“Finding Optimal Trading History in Reinforcement Learning for Stock Market Trading” 论文地址&#xff1a;https://arxiv.org/pdf/2502.12537 摘要 本文探讨了在金融深度强化学习模型中优化时间窗口的方法&#xff0c;并采用了二维卷积神经网络&#xff08;CNN&#x…

MATLAB学习之旅:图像处理与计算机视觉应用

在前面的学习中&#xff0c;我们已经深入了解了MATLAB在数据建模与仿真方面的强大功能。从基础的数据处理到复杂的模型构建与仿真分析&#xff0c;MATLAB为我们提供了丰富的工具和函数&#xff0c;帮助我们解决各种实际问题。如今&#xff0c;我们将迈向下一个充满挑战与创新的…

MediaToolkit:.NET 开发者的多媒体处理工具

在开发过程中处理音频和视频文件是许多应用程序的重要功能。MediaToolkit 是一个强大的库&#xff0c;帮助轻松处理这些多媒体文件。封装了 FFmpeg 的功能&#xff0c;使得复杂的任务变得简单。支持更多功能&#xff0c;如视频裁剪、缩略图提取和转码等。 安装 第一步&#x…