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

embedded/2025/2/27 16:53:55/

一、阻塞队列概述

  • 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)); // trueSystem.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)); // trueSystem.out.println(blockingQueue.remove()); // 1
System.out.println(blockingQueue.element()); // 2System.out.println(blockingQueue.remove()); // 2
System.out.println(blockingQueue.element()); // 3System.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)); // trueSystem.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)); // trueSystem.out.println(blockingQueue.poll()); // 1
System.out.println(blockingQueue.peek()); // 2System.out.println(blockingQueue.poll()); // 2
System.out.println(blockingQueue.peek()); // 3System.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"); // ablockingQueue.put(2);
System.out.println("b"); // bblockingQueue.put(3);
System.out.println("c"); // cblockingQueue.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)); // trueSystem.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.ppmy.cn/embedded/167575.html

相关文章

Java HTTP 请求的四种实现方式:Apache HttpClient、OkHttp、WebClient 与 Java 11 HttpClient

目录 1.使用Java11内置的HttpClient 2.使用OkHttp 3.使用SpringWebClient 4.使用ApacheHttpClient5.x 在现代Java开发中,HttpClient和PostMethod是较旧的ApacheHttpClient3.x的API。推荐使用更现代的技术来替代这些代码,例如Java11内置的HttpClient或…

QT零基础学习之路(四)--信号和槽机制

源码(更新更快):https://mp.weixin.qq.com/s/LvcjGiK6KSyoAB55qosgIQ

自然语言处理(NLP):文本向量化从文字到数字的原理

在人工智能领域,尤其是自然语言处理(NLP)中,将文本信息转化为机器可以理解的形式是一个至关重要的步骤。本文探讨如何将文本转换为向量表示的过程,包括分词、ID映射、One-hot编码以及最终的词嵌入(Embeddin…

126.单词接龙Ⅱ python

单词接龙Ⅱ 题目题目描述示例 1:示例 2:提示: 题解解决方案步骤Python 实现解释提交结果 题目 题目描述 按字典 wordList 完成从单词 beginWord 到单词 endWord 转化,一个表示此过程的 转换序列 是形式上像 beginWord -> s1 …

软件供应链安全工具链研究系列—RASP自适应威胁免疫平台(下篇)

在“软件供应链安全工具链研究系列—RASP自适应威胁免疫平台-上篇”中我们提到了RASP工具的基本能力、原理以及工具的应用场景,了解到了RASP工具在各场景下发挥的价值。那么在当今高强度攻防对抗的大场景下,RASP作为最后一道防线,不论是从高危…

系统架构设计:软件测试需要掌握的常用方法

软件测试是软件开发过程中不可或缺的一部分,其目的是确保软件产品的质量和性能。本文将详细介绍软件测试的重要知识点,并附上相关代码示例,帮助读者更好地理解和应用这些知识。 一、软件测试的定义与目的 1. 定义 软件测试是在规定的条件下对程序进行操作,以发现程序错误…

DeepSeek动画视频全攻略:从架构到本地部署

DeepSeek 本身并不直接生成动画视频,而是通过与一系列先进的 AI 工具和传统软件协作,完成动画视频的制作任务。这一独特的架构模式,使得 DeepSeek 在动画视频创作领域发挥着不可或缺的辅助作用。其核心流程主要包括脚本生成、画面设计、视频合成与后期处理这几个关键环节。 …

初会学习记录

【25初级会计《实务》】第一章:权责发生制举例_哔哩哔哩_bilibili 务实: 第一章 (1)会计概念,职能和目标: 2025年2月25日: (2)会计假设: 2025年2月26日: (3)会计核算基础: 202…