深入理解 Java 阻塞队列:使用场景、原理与性能优化

在并发编程中,线程安全的队列是解决线程间任务传递和调度的关键工具之一。阻塞队列(BlockingQueue)作为一种线程安全的队列,实现了在并发环境下对共享数据的安全访问,广泛应用于生产者-消费者模型、任务调度和多线程计算中。本文将详细介绍阻塞队列的概念、常见实现、线程安全原理及与线程池的结合使用,帮助你全面掌握 Java 中阻塞队列的应用。

1. 什么是阻塞队列

阻塞队列(BlockingQueue)是一个线程安全的队列,它支持在特定条件下对队列的操作进行阻塞。BlockingQueue 接口继承自 Queue,并提供了几个核心方法:take()put()offer()poll(),其中 take()put() 是阻塞操作,能够在队列为空时等待数据,或在队列满时等待空闲空间。

public interface BlockingQueue<E> extends Queue<E> {void put(E e) throws InterruptedException;E take() throws InterruptedException;boolean offer(E e);E poll();// 其他方法
}

应用场景:

  • 生产者消费者模型:多个生产者线程将任务放入队列,多个消费者线程从队列中取出任务执行,队列的大小决定了系统的缓冲能力。
  • 任务调度:队列可以用来调度和管理任务,保证任务的顺序执行和线程间的协调。

2. 主要的并发队列关系图

Java 提供了多种线程安全的队列,主要可以分为两类:

  • 阻塞队列(BlockingQueue)
  • 非阻塞队列(如 ConcurrentLinkedQueue

这两类队列各自适用于不同的场景,阻塞队列适合于需要控制线程协作的场景,非阻塞队列则适合于高并发、高性能的无阻塞任务处理。

3. 阻塞队列的特点

阻塞队列的最大特点是它的阻塞操作,主要体现在以下两个方法:

  • take():如果队列为空,消费者线程会被阻塞,直到队列中有数据可用。
  • put():如果队列已满,生产者线程会被阻塞,直到队列有空闲空间。

这些方法的阻塞特性使得阻塞队列非常适合于生产者-消费者模型,它能够保证任务的有序执行,并且自动控制线程的执行顺序。

4. 常用方法

常见的 BlockingQueue 方法包括:

  • add():向队列中添加元素,队列已满时抛出异常。
  • remove():移除并返回队列头部的元素,队列为空时抛出异常。
  • offer():向队列中添加元素,队列已满时返回 false
  • poll():移除并返回队列头部的元素,队列为空时返回 null
  • put():向队列中添加元素,队列已满时阻塞当前线程,直到有空间可用。
  • take():从队列中获取并移除元素,队列为空时阻塞当前线程,直到有数据可用。

5. 常见阻塞队列

Java 提供了多种实现了 BlockingQueue 接口的常见阻塞队列,每种队列的实现都具有不同的特点,适用于不同的应用场景。

5.1 ArrayBlockingQueue

ArrayBlockingQueue 是一个有界阻塞队列,内部使用数组存储元素,具有固定的容量,适用于任务数已知且较为稳定的场景。

BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(10);

5.2 LinkedBlockingQueue

LinkedBlockingQueue 是一个基于链表的阻塞队列,可以设置容量,容量默认值为 Integer.MAX_VALUE。适用于任务量动态变化的场景。

BlockingQueue<Integer> queue = new LinkedBlockingQueue<>(100);

5.3 SynchronousQueue

SynchronousQueue 是一种特殊的阻塞队列,其容量为 0。每次生产任务时,必须有消费者线程来接收该任务,否则生产者会被阻塞。适用于快速传递任务的场景。

BlockingQueue<Integer> queue = new SynchronousQueue<>();

5.4 PriorityBlockingQueue

PriorityBlockingQueue 是一个无界的阻塞队列,支持优先级排序,队列中的元素根据优先级进行排序,适用于需要处理优先级任务的场景。

BlockingQueue<Integer> queue = new PriorityBlockingQueue<>();

5.5 DelayQueue

DelayQueue 是一个支持延时任务的无界阻塞队列,任务可以设置延迟时间,任务到期后才会被消费。适用于定时任务调度的场景。

BlockingQueue<Delayed> queue = new DelayQueue<>();

6. 阻塞和非阻塞队列的并发安全原理

6.1 ArrayBlockingQueue 源码分析

ArrayBlockingQueue 内部使用数组存储元素,使用 ReentrantLockCondition 实现并发控制。put()take() 方法会通过 lock 锁住队列,阻塞操作使用 notFullnotEmpty 条件变量来控制线程的同步。

public void put(E e) throws InterruptedException {lock.lockInterruptibly();try {while (count == items.length)notFull.await();enqueue(e);} finally {lock.unlock();}
}
  • ReentrantLock:提供了对队列的独占锁,确保线程在操作队列时是互斥的。
  • Condition:通过 notFullnotEmpty 条件变量来控制线程的等待和唤醒。

6.2 非阻塞队列 ConcurrentLinkedQueue

ConcurrentLinkedQueue 是一个无界的非阻塞队列,内部通过 CAS(Compare-And-Swap)机制实现线程安全,适用于高并发场景。它使用 compareAndSwapObject 方法进行原子操作,保证多个线程同时访问队列时不发生冲突。

public boolean offer(E e) {final Node<E> newNode = new Node<>(e);for (Node<E> t = tail, p = t;;) {Node<E> q = p.next;if (q == null) {if (p.casNext(null, newNode)) {if (p != t)casTail(t, newNode);return true;}}p = q;}
}

7. 线程池与阻塞队列

线程池与阻塞队列常常一起使用,阻塞队列作为线程池的任务队列,用于存储待处理的任务。常见的线程池类型及其与阻塞队列的配合关系如下:

线程池类型阻塞队列类型
FixedThreadPoolLinkedBlockingQueue
SingleThreadExecutorLinkedBlockingQueue
CachedThreadPoolSynchronousQueue
ScheduledThreadPoolDelayWorkQueue
SingleThreadScheduledExecutorDelayedWorkQueue

7.1 LinkedBlockingQueue

适用于 FixedThreadPoolSingleThreadExecutor,由于这两个线程池的线程数固定,任务队列的容量可以设置较大,确保不会因为队列满而拒绝任务。

7.2 SynchronousQueue

适用于 CachedThreadPool,它的容量为 0,每个任务都会立即被执行,因此线程池的线程数可以动态变化。

7.3 DelayWorkQueue

适用于定时任务,如 ScheduledThreadPoolSingleThreadScheduledExecutor,能够根据任务的延迟时间进行调度。

总结

阻塞队列是并发编程中的一个重要工具,它通过线程安全的队列机制,保证了在多线程环境下的数据传递和协调。Java 提供了多种实现方式,如 ArrayBlockingQueueLinkedBlockingQueueSynchronousQueue 等,可以根据不同的业务需求选择合适的阻塞队列类型。掌握阻塞队列的使用和原理,能够帮助你构建更加高效和可靠的并发程序。

🌟 关注我的CSDN博客,收获更多技术干货! 🌟

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/60638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

.NET9 - 新功能体验(二)

书接上回&#xff0c;我们继续来聊聊.NET9和C#13带来的新变化。 01、新的泛型约束 allows ref struct 这是在 C# 13 中&#xff0c;引入的一项新的泛型约束功能&#xff0c;允许对泛型类型参数应用 ref struct 约束。 可能这样说不够直观&#xff0c;简单来说就是Span、ReadO…

抗癌药物“曲妥珠单抗”,或将纳入2025版《中国药典》!

在抗癌药物的浩瀚星空中&#xff0c;曲妥珠单抗如同一颗璀璨的星辰&#xff0c;以其卓越的治疗效果和广泛的应用前景&#xff0c;照亮了无数HER2阳性癌症患者的生命之路。近日&#xff0c;从国家药典委员会传来振奋人心的消息——注射用曲妥珠单抗正式进入《中国药典》2025版国…

JavaParser 的全面介绍

JavaParser 是什么&#xff1f; JavaParser 的快速介绍可以参考&#xff1a; # JavaParser的快速介绍 JavaParser是一个用于解析Java源码的开源工具&#xff0c;它提供了一种简单而有效的方式来解析和操作Java代码。JavaParser解析源码的方式主要基于其将Java代码转换为抽象语…

图形化界面MySQL(MySQL)(超级详细)

1.官网地址 MySQL :: Download MySQL Workbench 1.1在Linux直接点击NO thanks..... 下载完后是这个页面 1.2任何远端登录&#xff0c;再把jj数据库给授权 1.3建立新用户 进行连接 点击这个就运行了 只执行show tables&#xff1b;要先选中 圆圈处支持自己输入 点击这个就执…

【夹板涨停战法】技术形态,原理和操盘技术图文教程

夹板涨停战法的基本形态和原理 夹板涨停是指两股强大的做多力量以夹击的方式紧紧的封夹空头&#xff0c;把空头力量打趴下&#xff0c;让空头的做空希望被破灭。 两股强大的多头力量对付空头&#xff0c;多头战胜&#xff0c;轻易灭掉空头&#xff0c;一切在强大做多力量的把…

【2024 Optimal Control 16-745】Julia语法

Lecture 2 θ和它的导数符号是通过 Julia 中的变量命名方式实现的 变量 θ 的输入&#xff1a; 在 Julia 中&#xff0c;θ 是一个合法的变量名&#xff0c;就像普通的字母 x 或 y 一样。要输入 θ&#xff0c;可以使用以下方法&#xff1a; 在 Jupyter Notebook 或 Julia REP…

Java项目实战II基于SPringBoot的玩具销售商城管理系统(开发文档+数据库+源码)

目录 一、前言 二、技术介绍 三、系统实现 四、核心代码 五、源码获取 全栈码农以及毕业设计实战开发&#xff0c;CSDN平台Java领域新星创作者&#xff0c;专注于大学生项目实战开发、讲解和毕业答疑辅导。获取源码联系方式请查看文末 一、前言 随着儿童娱乐与教育需求的…

Linux系统使用valgrind分析C++程序内存资源使用情况

内存占用是我们开发的时候需要重点关注的一个问题&#xff0c;我们可以人工根据代码推理出一个消耗内存较大的函数&#xff0c;也可以推理出大概会消耗多少内存&#xff0c;但是这种方法不仅麻烦&#xff0c;而且得到的只是推理的数据&#xff0c;而不是实际的数据。 我们可以…

stm32如何接收舵机的控制信号(而不是控制舵机)

看到很多如何stm32用pwm信号控制舵机的文章,老生常谈了 我来写一个stm32接收pwm信号的例子 ,这个pwm信号是用来控制舵机的 背景: 我需要接收航模接收机的,用来控制舵机的pwm信号, 得到这个信号后,做其他事情. 初版代码 pwm.h#ifndef _pwm_H #define _pwm_H#include "s…

RK3588 HDMI2.1电路参考设计原理

RK3588是瑞芯微电子&#xff08;Rockchip&#xff09;旗下的一款高性能应用处理器芯片&#xff0c;采用了ARM的big.LITTLE架构&#xff0c;结合了四个高性能的Cortex-A76核心和四个高效能的Cortex-A55核心。 big.LITTLE技术通过结合高性能的“大核”&#xff08;big cores&…

【大数据学习 | Spark-Core】详解分区个数

RDD默认带有分区的&#xff0c;那么创建完毕rdd以后他的分区数量是多少&#xff1f; 从hdfs读取文件的方式是最正规的方式&#xff0c;我们通过计算原理可以推出blk的个数和分区数量是一致的&#xff0c;本地化计算。 我们可以发现数据的读取使用的是textInputFormat&#xff…

艾体宝干货丨差异解读:IT 和 OT 网络的数据包和网络分析

IT 网络&#xff08;传统网络&#xff09; IT 网络是现代计算的支柱&#xff0c;为数据交换、通信和处理提供了基础设施。典型应用包括 办公网络数据中心云服务互联网连接 这些网络依靠 TCP/IP、DNS 和 HTTP 等标准协议来促进设备之间的通信。通信路径可能随时发生变化&…

AOC显示器915Sw按键失灵维修记

大家好&#xff0c;我是 程序员码递夫 今天给大家分享的是自己维修老古董AOC液晶显示器按键失灵的的过程&#xff0c;实属DIY记录。 1、引子 家里有台老古董的19寸AOC液晶显示器&#xff08;型号915Sw&#xff09;, 一直作为我的副显示器陪伴着左右&#xff0c;显示还正常&a…

Vscode进行Java开发环境搭建

Vscode进行Java开发环境搭建 搭建Java开发环境(Windows)1.Jdk安装2.VsCode安装3.Java插件4.安装 Spring 插件5.安装 Mybatis 插件5.安装Maven环境6.Jrebel插件7.IntelliJ IDEA Keybindings8. 收尾 VS Code&#xff08;Visual Studio Code&#xff09;是由微软开发的一款免费、开…

【MATLAB源码-第218期】基于matlab的北方苍鹰优化算法(NGO)无人机三维路径规划,输出做短路径图和适应度曲线.

操作环境&#xff1a; MATLAB 2022a 1、算法描述 北方苍鹰优化算法&#xff08;Northern Goshawk Optimization&#xff0c;简称NGO&#xff09;是一种新兴的智能优化算法&#xff0c;灵感来源于北方苍鹰的捕猎行为。北方苍鹰是一种敏捷且高效的猛禽&#xff0c;广泛分布于北…

戴尔 AI Factory 上的 Agentic RAG 搭载 NVIDIA 和 Elasticsearch 向量数据库

作者&#xff1a;来自 Elastic Hemant Malik, Dell Team 我们很高兴与戴尔合作撰写白皮书《戴尔 AI Factory with NVIDIA 上的 Agentic RAG》。白皮书是一份供开发人员参考的设计文档&#xff0c;概述了实施 Agentic 检索增强生成 (retrieval augmented generation - RAG) 应用…

第十六届蓝桥杯模拟赛(第一期)-Python

本次模拟赛我认为涉及到的知识点&#xff1a; 分解质因数 Python的datetime库 位运算 简单dp 1、填空题 【问题描述】 如果一个数 p 是个质数&#xff0c;同时又是整数 a 的约数&#xff0c;则 p 称为 a 的一个质因数。 请问 2024 有多少个质因数。 【答案提交】 这是一道结…

统⼀数据返回格式快速⼊⻔

为什么会有统⼀数据返回&#xff1f; 其实统一数据返回是运用了AOP&#xff08;对某一类事情的集中处理&#xff09;的思维。 优点&#xff1a; 1.⽅便前端程序员更好的接收和解析后端数据接⼝返回的数据。 2.降低前端程序员和后端程序员的沟通成本&#xff0c;因为所有接⼝都…

数据库中的增删改查操作、聚合函数、内置函数、分组查询

数据库中的增删改查操作、聚合函数、内置函数、分组查询 CRUD简介Create 新增语法示例单⾏数据全列插⼊单⾏数据指定列插⼊多⾏数据指定列插⼊ Retrieve 检索语法⽰例构造数据 Select全列查询指定列查询查询字段为表达式为查询结果指定别名语法⽰例 结果去重查询 Order by 排序…

SpringBoot项目部署到云服务器全流程

文章目录 一、前期准备&#xff08;一&#xff09;云服务器选择&#xff08;二&#xff09;本地环境准备&#xff08;三&#xff09;数据库准备&#xff08;若项目需要&#xff09; 二、服务器配置&#xff08;一&#xff09;获取服务器信息&#xff08;二&#xff09;重置实例…