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

news2024/11/26 3:06:14

在并发编程中,线程安全的队列是解决线程间任务传递和调度的关键工具之一。阻塞队列(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.coloradmin.cn/o/2247605.html

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

相关文章

JS的DOM操作和事件监听综合练习 (具备三种功能的轮播图案例)

下面是是对dom操作的一个综合练习 下面代码是html的基本骨架&#xff08;没有任何的功能&#xff09;&#xff1a; <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" c…

GitHub 开源项目 Puter :云端互联操作系统

每天面对着各种云盘和在线应用&#xff0c;我们常常会遇到这样的困扰。 文件分散在不同平台很难统一管理&#xff0c;付费订阅的软件越来越多&#xff0c;更不用说那些烦人的存储空间限制了。 最近在 GitHub 上发现的一个开源项目 Puter 彻底改变了我的在线办公方式。 让人惊…

鸿蒙进阶篇-状态管理之@Provide与@Consume

大家好&#xff0c;这里是鸿蒙开天组&#xff0c;今天我们来学习一下状态管理中的Provide与Consume。 一、概述 嘿&#xff01;大家还记得这张图吗&#xff1f;不记得也要记得哦&#xff0c;因为这张图里的东西&#xff0c;既是高频必考面试题&#xff0c;也是实际开发中&…

Python 使用 OpenCV 将 MP4 转换为 GIF图

以下是使用 Python 和 OpenCV 将 MP4 转换为 GIF 的示例代码&#xff1a; python import cv2 import imageiodef mp4_to_gif(mp4_path, gif_path, fps10, start_timeNone, end_timeNone):"""将MP4视频转换为GIF动图。:param mp4_path: 输入MP4视频的路径。:pa…

五天SpringCloud计划——DAY1之mybatis-plus的使用

一、引言 咱也不知道为啥SpringCloud课程会先教mybatis-plus的使用&#xff0c;但是教都教了&#xff0c;就学了吧&#xff0c;学完之后觉得mybatis-plus中的一些方法还是很好用了&#xff0c;本文作为我学习mybatis-plus的总结提升&#xff0c;希望大家看完之后也可以熟悉myba…

TCP为什么需要三次握手?两次握手或四次握手可以吗?

&#xff08;1&#xff09;三次握手可以保证双方具有接收和发送的能力 第一次握手服务端可以确认客户端的发送能力和服务端的接收能力是正常的&#xff1b;第二次握手客户端可以确认客户端和服务端的收发能力是正常的&#xff0c;但是服务端无法确认客户端的接收能力是正常的&…

Python 获取微博用户信息及作品(完整版)

在当今的社交媒体时代&#xff0c;微博作为一个热门的社交平台&#xff0c;蕴含着海量的用户信息和丰富多样的内容。今天&#xff0c;我将带大家深入了解一段 Python 代码&#xff0c;它能够帮助我们获取微博用户的基本信息以及下载其微博中的相关素材&#xff0c;比如图片等。…

vue面试题——描述一下vue

目录 1 vue是什么2 Vue的核心特性2.1 数据驱动&#xff08;MVVM&#xff09;2.2 组件化2.3 指令系统 3 Vue跟传统开发的区别 1 vue是什么 简单点说&#xff0c;vue就是一个用于创建用户界面的JavaScript框架&#xff0c;同时也是一个创建单页面应用的Web应用框架&#xff0c;Vu…

Large Spatial Model:End-to-end Unposed Images to Semantic 3D 论文解读

目录 一、概述 二、相关工作 1、SfM和可微神经表示 2、端到端的Image-to-3D 三、LSM 1、密集几何预测 2、2D信息特征提取 3、点特征融合 4、可微渲染 5、损失函数 四、实验 一、概述 该论文提出一种大型空间模型&#xff08;Larget Spatial Model,LSM&#xff09;…

A045-基于spring boot的个人博客系统的设计与实现

&#x1f64a;作者简介&#xff1a;在校研究生&#xff0c;拥有计算机专业的研究生开发团队&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的网站项目。 代码可以查看文章末尾⬇️联系方式获取&#xff0c;记得注明来意哦~&#x1f339; 赠送计算机毕业设计600…

VMware17安装之VMware Workstation Pro 16升级到17详细教程

VMware17安装之VMware Workstation Pro 16升级到17详细教程 一、下载安装包二、开始安装三、升级成功 当前使用的是VMware Workstation 16 Pro版本&#xff0c;想用最新的17&#xff0c;但是又不想卸载原来的&#xff0c;所以想尝试下看看能不能直接升级&#xff0c;最终升级成…

nature communications论文 解读

题目《Transfer learning with graph neural networks for improved molecular property prediction in the multi-fidelity setting》 这篇文章主要讨论了如何在多保真数据环境&#xff08;multi-fidelity setting&#xff09;下&#xff0c;利用图神经网络&#xff08;GNNs&…

接口上传视频和oss直传视频到阿里云组件

接口视频上传 <template><div class"component-upload-video"><el-uploadclass"avatar-uploader":action"uploadImgUrl":on-progress"uploadVideoProcess":on-success"handleUploadSuccess":limit"lim…

深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录

深度学习图像视觉 RKNN Toolkit2 部署 RK3588S边缘端 过程全记录 认识RKNN Toolkit2 工程文件学习路线&#xff1a; Anaconda Miniconda安装.condarc 文件配置镜像源自定义conda虚拟环境路径创建Conda虚拟环境 本地训练环境本地转换环境安装 RKNN-Toolkit2&#xff1a;添加 lin…

07-SpringCloud-Gateway新一代网关

一、概述 1、Gateway介绍 官网&#xff1a;https://spring.io/projects/spring-cloud-gateway Spring Cloud Gateway组件的核心是一系列的过滤器&#xff0c;通过这些过滤器可以将客户端发送的请求转发(路由)到对应的微服务。 Spring Cloud Gateway是加在整个微服务最前沿的防…

美创科技入选2024数字政府解决方案提供商TOP100!

11月19日&#xff0c;国内专业咨询机构DBC德本咨询发布“2024数字政府解决方案提供商TOP100”榜单。美创科技凭借在政府数据安全领域多年的项目经验、技术优势与创新能力&#xff0c;入选收录。 作为专业数据安全产品与服务提供商&#xff0c;美创科技一直致力于为政府、金融、…

Java编程,配置mongoUri连接mongodb时,需对特殊字符进行转义

一、背景 java程序连接mongo有两种方式&#xff1a; 用户名和密码方式uri方式 1、用户名和密码 以用户数据库为例&#xff0c;注意看它的密码 spring:data:mongodb:host: 192.168.10.17database: db_user_serviceport: 3717username: user_servicepassword: user_service3…

MySQL底层概述—1.InnoDB内存结构

大纲 1.InnoDB引擎架构 2.Buffer Pool 3.Page管理机制之Page页分类 4.Page管理机制之Page页管理 5.Change Buffer 6.Log Buffer 1.InnoDB引擎架构 (1)InnoDB引擎架构图 (2)InnoDB内存结构 (1)InnoDB引擎架构图 下面是InnoDB引擎架构图&#xff0c;主要分为内存结构和磁…

【Github】如何使用Git将本地项目上传到Github

【Github】如何使用Git将本地项目上传到Github 写在最前面1. 注册Github账号2. 安装Git工具配置用户名和邮箱仅为当前项目配置&#xff08;可选&#xff09; 3. 创建Github仓库4. 获取仓库地址5. 本地操作&#xff08;1&#xff09;进入项目文件夹&#xff08;2&#xff09;克隆…

大事件管理系统项目总结(上)

文章目录 大事件管理系统项目总结&#xff08;上&#xff09;Pinia - 配置仓库统一管理Vue3路由配置Vue3导航拦截 大事件管理系统项目总结&#xff08;上&#xff09; Pinia - 配置仓库统一管理 使用pinia多层文件夹嵌套时&#xff0c;导入某个文件的路径会很长&#xff0c;容…