news 2026/2/6 18:18:36

字节二面:了解环形队列吗?有哪些使用场景?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
字节二面:了解环形队列吗?有哪些使用场景?

在日常开发工作中,环形队列的使用并不多,但其实环形队列是一个很有用的数据结构,而且有不少使用场景。今天来聊一聊环形队列的使用场景。

1.环形队列

队列这个数据结构最大的特点就是先进先出,它可以有两种实现方式,无界队列一般用链表来实现,有界队列可以用数组来实现。

但使用数组来实现队列,有新数据插入时,需要搬移元素,造成额外的性能开销。要解决数据搬移的问题,我们可以考虑使用环形队列。

下图是一个 8 个元素的环形队列:

环形队列的特点是写完最后一个元素后接着从头开始写,读元素也一样。初始状态,head 和 tail 都指向数据下标是 0 的位置。每写入一个元素,tail 往后移动一个指针,每读取一个元素,head 指针往后移动一个指针。如果写入的速度超过了读取速度一圈,未读取的元素就会被覆盖。

下图是用数组来表示的环形队列,尾节点指向头结点,实现首尾相连:

在上图中,head 所在数组位置元素值是 3,tail 所在数组位置元素值是 7。这时如果我们插入一个新元素 a,环形队列变成下图:

那环形队列代码怎么实现呢?这里给出一个示例代码:

public class CircleQueue { //实现环形队列的数组 private String[] items; //数组大小 private int size; //数组元素数量 private int count = 0; private int head = 0; private int tail = 0; //申请一个指定容量的队列 public CircleQueue(int size){ items = new String[size]; this.size = size; } public boolean enqueue(String item){ if ((tail + 1) % size == head){ //队列满 return false; } items[tail] = item; tail = (tail + 1) % size; count++; return true; } public String dequeue(){ String item = null; //队列空 if(head == tail){ return item; } item = items[head]; head = (head + 1) % size; count--; return item; } }

在上面的例子中,如果队列满了,就会写入消息失败。不过在实际使用场景中,有些场景如果队列满了,可以覆盖掉当前 tail 位置上的元素,tail 继续往下一个位置移动。这个适用于丢失数据影响较小的场景,比如记录日志。

2.使用场景

2.1 延时消息

在消息队列中,延时消息的使用场景很多,比如超过 30 分钟关闭未支付订单。主流消息队列实现延时关闭订单的方式是采用线程轮询的方式来判断订单是否超过 30 分钟,如果超过则关闭订单。

在 RocketMQ 5.0 之前,4.x 版本定义了 18 个延时级别:

private String messageDelayLevel = "1s 5s 10s 30s 1m 2m 3m 4m 5m 6m 7m 8m 9m 10m 20m 30m 1h 2h";

Broker 收到消息后,会根据延时级别把消息保存到同一个 Topic(SCHEDULE_TOPIC_XXXX)下的不同 queue。然后启动 18 个线程来对每个 queue 做轮询判断,如果时间到了,就把消息投递到原始队列,等待 Consumer 来拉取。

这样的设计存在一个问题,延时级别只有 18 个,不太灵活,对于大型的复杂业务系统,延时级别可能成千上万,这种设计无法满足。

为了解决这个设计问题,RocketMQ 5.0 基于时间轮算法引入了定时消息。如下图:

图中定义了一个 60s 的时间轮,时间轮上有一个指向当前时间的指针定时地移动到下一秒时间。

这样不用去轮询所有消息,每一个时间节点上的消息用链表串起来,当时间轮上的指针移动到当前的时间时,这个时间节点上符合条件的消息就交给异步线程来处理。

如果一个消息的延时时间超过 60s,比如 130s,该怎么设置呢?在每个时间轮节点增加一个 round 字段,记录时间轮转动的圈数,对于延时 130s 的消息,round 就是 2,放在第 10 个时间刻度的链表中。时间轮每转动一圈,round 值减一,这样当时间轮转到一个节点,处理节点上的消息时,首先判断 round 值是否等于 0,如果等于 0,则把这个消息从链表中移出交给异步线程执行,否则将 round 减 1 继续检查后面的任务。

2.2 Disruptor

Disruptor 是一款高性能的消息队列,它使用到了环形队列这个数据结构。那 Disruptor 使用环形队列是怎样做到高性能的呢?

2.2.1 内存预分配

Disruptor 使用循环队列,在队列初始化的时候,数组元素一次性初始化,这样可以不仅提升缓存命中率,还可以避免频繁 GC。

2.2.2 无锁并发

Disruptor 是一种生产者-消费者模式,当多个生产者在同一个位置写事件消息时,就会被覆盖。如下图,线程1 把位置 1 的元素更新成 b,线程 2 写入时本来应该在位置 2 写入 c,但是写入了位置 1,导致覆盖了线程 1 写入的值。消费者并发消费时也有类似的问题。

解决这个问题最好的方法就是给写入的代码加锁,只允许获取到锁的线程执行,但这样失去了并发优势,性能降低。

为了解决加锁带来的性能问题,Disruptor 在设计上进行了改造。当一个线程要写入循环队列时,先申请队列上连续的 n 个位置,申请成功这 n 个位置是线程独享的,这样线程在写入元素时就不用担心被覆盖。消费者进行并发消费时,也是先申请连续的 n 个位置独自消费,跟其他线程互相隔离。

2.2.3 解决伪共享

环形队列内部数组使用缓存行填充技术来避免伪共享问题,进一步提高了性能。

2.3 日志收集

dmesg 这个 Linux 命令我们应该了解过,主要用于查看系统启动时的日志信息、硬件信息。

dmesg 使用的日志就是存储在环形缓存区中,每当有新的日志写入时,如果环形队列已满,就会覆盖旧的日志,这样可以保证内核日志不会占用过多的内存空间,而且还能够不断记录新日志。

3.总结

环形队列作为一种有界循环队列,在消息中间件、高性能内存队列 Disruptor、日志收集等方面有广泛的应用。了解循环队列的原理,可以更好的理解它的使用场景。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/2/6 9:22:29

621-6550电源输出模块

621-6550 电源输出模块简介: 621-6550 是工业控制系统中使用的电源输出模块 主要用于为系统内其他模块或现场设备提供稳定电源 可将系统电源进行分配并输出到不同负载 适用于机架式或分布式控制系统结构 与控制器、电源输入模块配合使用 输出电压稳定&#xff…

作者头像 李华
网站建设 2026/2/7 0:51:24

621-9000逻辑控制器模块

621-9000 逻辑控制器模块简介: 621-9000 是工业自动化系统中的逻辑控制器模块 主要负责系统控制逻辑的运算与处理 可根据输入信号执行预设的控制程序 支持顺序控制、联锁控制等常见控制方式 用于协调各类输入、输出模块的工作 可作为控制系统的核心处理单元使用…

作者头像 李华
网站建设 2026/2/6 19:18:20

SpringAi-mcp高德

1.创建key 进入高德官网注册,创建key https://console.amap.com/dev/id/phone(官网) 2.编写yml文件 引入自己的key #高德的key AMAP-KEY: #自己的key,复制上 3.创建工具类 3.1AmapService package com.jiazhong.mingxing.ai.siliconflow.mcp.glm.service;im…

作者头像 李华
网站建设 2026/2/6 9:47:29

PDF转存CKEDITOR时文字重叠如何避免?

【穷学生の逆袭】99元预算搞定Word粘贴公式渲染的CMS升级方案 (附JSP后端Vue2代码接单群彩蛋🎉) 一、需求拆解与白嫖策略 作为川软大三狗,面对导师的"Word粘贴全家桶"需求,我摸了摸仅剩的99元,…

作者头像 李华
网站建设 2026/2/7 7:58:29

2026必备!专科生毕业论文AI论文工具TOP8测评

2026必备!专科生毕业论文AI论文工具TOP8测评 2026年专科生论文写作工具测评:为何需要这份榜单? 随着AI技术在教育领域的不断渗透,越来越多的专科生开始借助智能工具提升论文写作效率。然而,面对市场上五花八门的AI论…

作者头像 李华
网站建设 2026/2/6 10:00:11

粘贴WORD到CKEDITOR时表格变形如何处理?

军工级富文本内容迁移解决方案技术评估日志 2023年X月X日 于长沙研发中心 一、需求拆解与技术调研 1.1 核心需求矩阵 需求类型技术指标信创要求Word粘贴保留形状/表格/公式等复杂样式,图片自动转存OSS支持银河麒麟V10飞腾FT-2000环境文档导入支持Office/PDF格式解…

作者头像 李华