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

news/2025/2/26 20:31:47/

一、阻塞队列概述

  • 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/news/1575083.html

相关文章

6.6.3 SQL数据查询(一)

文章目录 SELECT语句简单查询连接查询子查询聚集函数 SELECT语句 SELECT是用于查询的动词,基本格式为SELECT-FROM-WHERE,其中WHERE可选。SELECT对应投影运算,FROM对应笛卡尔积运算,WHERE对应选择运算。选择使用的条件表达式p可包含…

使用 idea ide 安装通义灵码 TONGYI Lingma插件,进行后端java springboot项目的用户用例的生成尝试及遇到问题的简单 处理方法。

1、打开idea环境,可以关掉项目,或者直接在环境里面进行搜索tongyi,就可以看到Plugins中有这个项,然后点击Install,就可以开始安装了,界面如下: 2、然后我们看评论,发现大家用的不是…

VMware虚拟机安装win10系统详细图文安装教程(附安装包) 2025最新版详细图文安装教程

文章目录 前言一、软件下载二、安装步骤1.创建新的虚拟机2.安装 Windows 10 系统: 前言 在计算机使用中,有时需借助虚拟机来拓展功能。VMware 虚拟机是强大的工具,能让我们在同一台电脑上运行多个系统。Windows 10 系统功能丰富、应用广泛。本教程将详细…

STM32编译过程

STM32编译过程 1. 编译过程介绍2. 程序的组成、存储与运行3. 编译工具链3.1 armcc 工具3.2 armasm 工具3.3 armlink 工具3.4 armar 工具3.5 fromelf 工具 4. MDK工程的文件类型 1. 编译过程介绍 编译MDK 软件使用的编译器是 armcc 和 armasm,它们根据每个 c/c 和汇编…

【Godot4.3】基于绘图函数的矢量蒙版效果与UV换算

概述 在设计圆角容器时突发奇想: 将圆角矩形的每个顶点坐标除以对应圆角矩形所在Rect2的size,就得到了顶点对应的UV坐标。然后使用draw_colored_polygon,便可以做到用图片填充圆角矩形的效果。而且这种计算的效果就是图片随着其填充的图像缩…

PHP MySQL 创建数据库

PHP MySQL 创建数据库 引言 在Web开发中,数据库是存储和管理数据的重要工具。PHP作为一种流行的服务器端脚本语言,常与MySQL数据库结合使用。本文将详细介绍如何在PHP中使用MySQL创建数据库,并涵盖相关的基本概念和操作步骤。 MySQL数据库…

WPS接入私有化DeepSeek大语言模型

文章目录 1.安装officeAI软件1.1登录官网下载officeAI 2.officeAI相关配置2.1启动WPS第三方COM功能2.2接入本地ollama服务2.3演示示例 1.安装officeAI软件 OfficeAI 助手是一项专为 Microsoft Office 和 WPS 用户打造的智能办公工具软件,旨在解决多种常见办公问题。…

ubuntu网络及软件包管理

1、Ubuntu中如何设置IP地址 在 Ubuntu 中,可以通过几种方式设置 IP 地址:使用网络管理器图形界面、命令行工具(如 nmcli 或 nmtui)、或直接编辑网络配置文件。以下是这几种方法的详细步骤。 1.1、方法一:使用图形界面…