Java中阻塞队列原理、特点、适用场景

news2025/1/21 14:17:30

文章目录

    • 阻塞队列对比、总览
    • 阻塞队列本质思想
    • 主要队列讲解
      • ArrayBlockingQueue
      • LinkedBlockingQueue
      • SynchronousQueue
      • LinkedTransferQueue
      • PriorityBlockingQueue
      • DelayQueue
      • LinkedBlockingDeque

阻塞队列对比、总览

在这里插入图片描述

阻塞队列本质思想

阻塞队列都是线程安全的队列.
其最主要的功能就是当put元素的时候, 如果队列达到最大容量, 此时put线程可以自动阻塞,直到队列中有元素被取走.
当take元素的时候, 如果队列中元素为空, take线程会自动阻塞, 直到有元素被放入队列中.

那这个功能是怎样实现的呢?
其实最本质就是使用的Condition机制的await()和singnal(), 类似于synchronized中的wait()和notify().

当put元素时,发现队列中元素已满, 就调用await()方法, 阻塞当前线程, 而当有消费者获取元素后,不管有没有put线程被阻塞,都直接调用singnal()方法, 去尝试唤醒.这样就能达到效果.

Condition原理

Condition是要和lock配合使用的, 也就是Condition和ReentrantLock是绑定在一起的,而ReentrantLock底层实现其实是AQS.所以要想理解Condition的话,最好先理解AQS,不然可能会有云里雾里的感觉, 感兴趣的同学可以看看这篇文章

我们获取Condition对象可以使用lock.newCondition(),而这个方法实际上是会new出一个ConditionObject对象,该类是AQS的一个内部类.而AQS内部维护了一个同步队列,如果获取锁失败的话,会将线程放入该同步队列,同样的,condition内部也是使用同样的方式,其内部维护了一个等待队列

其大致原理如下:

  • 当awaitThread线程调用await方法后,会释放当前锁,挂起该线程, 将该线程加入到等待队列中

  • 当signalThread线程调用signal方法后,会将awaitThread线程从等待队列中移出,加入到同步队列中(此时没有唤醒),使awaitThread线程能够有机会获取到锁, 当signalThread线程真正释放锁之后, 处于同步队列中的awaitThread线程被唤醒,重新竞争获取锁, 然后执行剩下的代码.

主要队列讲解

ArrayBlockingQueue

ArrayBlockingQueue底层是以数组实现的有界阻塞队列.

我们讲所有阻塞队列都是线程安全的, 必然会用到锁, 它内部使用的是ReentrantLock.

那锁的是谁呢?

其实锁的就是这个数组对象, 因为数组是不可以变的, 存取元素都会操作这个数组.这样就能保证线程安全.

那数组是怎样实现队列的先进先出呢?

其实就是内部维护了两个指针, 每put一个新元素, puTIndex指针往后移一次,然后进行赋值; 取的时候就找takeIndex,取出后将该位置置为null.

这两个指针都是从左向右进行移动的, 移动到末尾会自动回到首位.
在这里插入图片描述

LinkedBlockingQueue

LinkedBlockingQueue 是用链表实现的 无界 阻塞队列.

因为是链表实现的, 所以它可以动态扩容, 初始可以指定容量.

我们想一想对于链表来说, 我们每次put, 其实都需要新new一个节点, 而take则是取原有节点, 所以它读和写是不影响的.所以它有两把锁.

存放元素和获取元素是两个不同的锁对象, 这样就足以保证线程安全.所以它其实就实现了锁分离, 读写不会相互阻塞, put和take是可以同时进行的,在并发量高的时候性能会高一些

在这里插入图片描述

在这里插入图片描述

SynchronousQueue

SynchronousQueue是Java并发包中提供的一种特殊类型的阻塞队列。它是一种没有容量的队列,每个插入操作必须等待另一个线程的相应移除操作,反之亦然。

它完成线程间数据交换是同步的, 也就是当你put一个元素就会直接被阻塞, 只有这个元素被take之后,put线程才会被唤醒.

其实如果只有一个线程put,一个线程take,那这个还是很容易实现的
但是其实我们可能有很多个线程put,很多个线程take,又要完成同步的数据交换.
这个怎么实现呢?

首先如果很多个线程put, 那这些线程都会被阻塞, 那这些线程所带的元素应该放哪呢?
所以需要一个容器, 去存储元素,并不是很多人理解的SynchronousQueue是没有存储容器的

这个容器其实就是以Node节点构成的队列, 当put元素的时候, 把put线程中携带的元素封装成Node节点,同时该节点还存储了当前put线程,也就是绑定该线程.然后将该线程阻塞. 一直阻塞到该Nodo的节点被take之后, 再唤醒put线程.从而实现同步.

在这里插入图片描述

由于SynchronousQueue需要一对线程进行插入和移除操作,因此需要额外的线程协调来保证操作的成功。如果某个线程插入元素而没有其他线程移除,或者某个线程移除元素而没有其他线程插入,那么可能会导致线程阻塞,甚至死锁。

LinkedTransferQueue

如果理解了LinkedBlockingQueue和SynchronousQueue,那LinkedTransferQueue也很好理解了.

但是它有一个很大的特点, 结合了LinkedBlockingQueue和SynchronousQueue的特点.
你可以自己控制放元素是否需要被阻塞

比如使用put方法就不会阻塞,立即返回
而使用transfer方法就会阻塞线程,等待被消费者消费

而取元素基本和SynchronousQueue一样,都会阻塞直到有新的元素可以被取出.

PriorityBlockingQueue

PriorityBlockingQueue是一个可以实现优先级任务的并发阻塞队列,它继承自BlockingQueue接口,实现了一个基于优先级的无界阻塞队列。它的特点是当多个线程同时插入元素时,会按照元素的优先级进行排序,并且可以保证在获取元素时,总是返回优先级最高的元素

那是怎样实现的呢?

它的底层数据结构是一个数组实现的平衡二叉树, 并且是一个最小堆,最小堆的特点是每个节点的值都小于或等于其子节点的值. 所以它的根节点一定是最小的值

在这里插入图片描述

而每次返回的优先级最高的元素也就是这个根节点, 当前的最小值.
当然, 每次取元素或者存元素都需要排序. 性能也会受到一定影响.

DelayQueue

DelayQueue允许将任务按照延迟时间进行排序,保证了任务按照预定的时间顺序执行。这对于需要在特定时间执行任务的场景非常有用,比如定时任务、延迟队列等。

它底层使用的是PriorityQueue, 和上面讲的PriorityBlockingQueue很类似, 只不过本身没有阻塞的功能, 阻塞功能由DelayQueue自己实现.

而PriorityQueue队列会根据元素的延迟时间自动排序。元素的延迟时间越短,它就越靠近队列头部,即优先级高. 当获取元素时, 会判断头部元素是否已经超过延迟时间, 超过则进行取出, 否则就进行阻塞.

LinkedBlockingDeque

LinkedBlockingDeque是一个基于链表的双向阻塞队列,它可以在队列的两端进行插入和删除操作.

它的实现基本和LinkedBlockingQueue类似,但是可以支持两边操作, 比如在两边同时进行插入操作.
但是也是由于这个不同点, 为了两边同时操作时的线程安全, 它存取是用的同一把锁, 这也是一个区别点.

今天的分享就到这里了,有问题可以在评论区留言,均会及时回复呀.
我是bling,未来不会太差,只要我们不要太懒就行, 咱们下期见.
在这里插入图片描述

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

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

相关文章

3分钟基于Chat GPT完成工作中的小程序

1. 写在前面 GPT自从去年爆发以来,各大公司在大模型方面持续发力,行业大模型也如雨后春笋一般发展迅速,日常工作中比较多的应用场景还是问答模式,作为写程序的辅助也偶尔使用。今天看到一篇翻译的博客“我用 ChatGPT,…

python通过socket 搭建极简web服务器

环境:win11、python 3.9.2 背景:python的web框架众多,常见的如django、flask、tornado等,其底层是什么还是有些许的疑问,所以查找相关资料,实现浏览器访问,并返回相关信息 时间:20…

期权定价模型系列【8】:选择者期权(chooser option)定价模型

期权定价模型系列第8篇文章 1.前言 抉择型期权又称为随心所欲期权,是一种与时间相关的期权。这种期权的持有 人有权在到期日之前的某一段时期,决定该选择权为买权或卖权。因此,在决定的时间点,抉择型期权的价值应该为:…

命令解释器-Shell

目录 1. 概述 1.1. 概念 1.2. 分类: 1.3. type 命令 1.4.命令执行原理 2. Linux 中的特殊符号 3. 命令别名 3.1. 查看设置的别名 3.2. 常用的别名 3.3. 删除别名 3.6. 注意(alias永久化): 4. history 命令历史 例&a…

已解决:win的资源管理器右键菜单被折叠无法显示全内容?教你解决

win11在样式上整挺好的,那种圆润感是win10没法比拟的,但是有一个很严重的诟病,就是右键菜单的折叠,这个东西是资源管理器新增的一个功能,如果之前是win右键的重度用户,那么对于这种需要多点一步展开的操作&…

解决报错: require is not defined in ES module scope

用node启动mjs文件报错:require is not defined in ES module scope 现象如下: 原因: 文件后缀是mjs, 被识别为es模块,但是node默认是commonjs格式,不支持也不能识别es模块。 解决办法:把文件后缀从.mjs改…

【进阶C语言】排序函数(qsort)与模拟实现(回调函数的实例)

本章大致内容目录: 1.认识回调函数 2.排序函数qsort 3.模拟实现qsort 回调函数为C语言重要知识点,以函数指针为主要知识;下面介绍回调函数的定义、回调函数的库函数举例即库函数模拟实现。 一、回调函数 1.回调函数定义 回调函数就是一…

16哈希表-基础操作

目录 哈希表 散列思想 哈希表的实现 简单示例 开胃菜:LeetCode之路——242. 有效的字母异位词 分析 哈希表 英文名字为Hash table,散列表的英文叫“Hash Table”,我们平时也叫它“哈希表”或者“Hash表”。 哈希表(Hash Ta…

vue3中使用return语句返回this.$emit(),在同一行不执行,换行后才执行,好奇怪!

今天练习TodoList任务列表案例,该案例效果如图所示: 此案例除了根组件App.vue,还有TodoList、TodoInput、TodoButton三个子组件。 因为有视频讲解,在制作TodoList、TodoInput时很顺利,只是在完成TodoButton这个组件时出了点问题…

VR开发(一)——SteamVR实现摇杆移动

一、基础环境搭建 1.AssetStore 找到SteamVR并导入; 2.添加一个 VR 中代表玩家自己的物体。我可以打开 Assets/SteamVR/InteractionSystem/Core 文件夹,将 Player 物体拖入场景: 二、修改手柄按钮映射集 3.windows/steamVR input&#xff…

【程序员必看】计算机网络,快速了解网络层次、常用协议和物理设备!

文章目录 0 引言1 基础知识的定义1.1 计算机网络层次1.2 网络供应商 ISP1.3 猫、路由器、交换机1.4 IP协议1.5 TCP、UDP协议1.6 HTTP、HTTPS、FTP协议1.7 Web、Web浏览器、Web服务器1.8 以太网和WLAN1.9 Socket (网络套接字) 2 总结 0 引言 在学习的过程…

OpenResty编译安装详解

文章目录 一、概述1、OpenResty是什么2、官方文档 二、cengos安装OpenResty1、从官网下载2、目录结构3、编译安装 一、概述 1、OpenResty是什么 OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖…

【Word】公式编辑器中连字符/减号等显示偏长/过长

问题 当公式编辑器中出现连字符的时候,连字符显示偏长,如下图所示: 方法 在连字符的前后加上双引号后即可解决连字符显示偏长的问题。 最终效果对比如下: 结语 Word的公式编辑器中,双引号内部的内容被当做普通…

基于FastAPI的文件上传和下载

基于FastAPI的文件上传和下载 一、前言 为了实现ASR的可视化界面,在各个博客中寻觅了一波找找文件上传和下载的例子,没有找到能完整实现这个功能的,有也只是有一部分(菜菜求捞捞),看了甚是烦恼&#xff0…

DBC配置SecOC属性

关联文章:Autosar基础——车载信息安全SecOC 属性定义的规范详细介绍请参考 ①dbc属性定义 ②Vector DBC属性定义规则 文章目录 一、SecOC简介二、DBC文件中的SecOC属性三、配置SecOC属性设置SecOC的属性设置同步报文的属性设置同步请求报文的属性一、SecOC简介 在车载网络中…

怎么利用互联网赚钱,网上赚钱的7种方法

互联网的兴起改变了我们的生活方式,不仅让我们的世界更为便捷,也为我们提供了赚钱的机会。越来越多的人开始通过互联网实现财富梦想。你是否曾想过,如何利用互联网来赚钱呢?今天,我将为大家分享七种赚钱方法&#xff0…

数据分析篇-数据认知分析

一简介 数据认知分析,实际是对数据的整体结构和分布特征进行分析,是对整个数据外在的认识,也是数据分析的第一步。对于数据认知的分析,一般会考虑分散性、位置特性、变量的相关性等,一般会考虑平均数、方差、极差、峰…

算法通过村第十二关-字符串|白银笔记|经典面试题

文章目录 前言1. 反转问题1.1 反转字符串1.2 k个一组反转1.3 仅仅反转字母1.3.1 采用栈实现操作1.3.2 采用双指针实现操作 1.4 反转字符串里面的单词1.4.1 使用语言提供的方法来解决(内置API)1.4.2 如何优雅自己实现上述功能 2. 验证回文串3. 字符串中的第一个唯一字符4. 判断是…

SaaS 电商设计 (二) 全链路解决方案概述和核心业务流程梳理

一.业务目标&技术目标 业务目标:完成多业态,多渠道的数字化运营 自有业务: O2O,B2C,B2B2C,S2B2b 平台业务:POPB2c,POPB2b,POPS2B2b 1.1 自有业务 O2O:全称Online to Offline.泛指的线上线下的业务融合.这种的情况分为两种情况,第一种通过线上的数字化运营引导线上用户线下…