【JUC进阶】12. 环形缓冲区

news2024/12/27 12:42:24

目录

1、前言

2、基本概述

2.1、什么是环形缓冲区

2.2、结构刨析

2.3、优点

2.4、缺点

3、如何使用

3.1、定义一个环形缓冲区

3.2、Demo使用


1、前言

上一篇《【JUC进阶】11. BlockingQueue》中介绍到ArrayBlockingQueue,在物理上是一个数组,但在逻辑上来说是个环形结构。这就衍生出来我们今天要介绍的主题,环形缓冲区。

2、基本概述

2.1、什么是环形缓冲区

环形缓冲区(Circular Buffer)是一种数据结构,它允许我们在固定大小的缓冲区中高效地存储和读取数据。这种缓冲区通常用于处理流式数据,例如网络数据流或文件数据流。

他之所以被称为环形缓冲区,因为它循环存储数据。数据以 FIFO(先进先出)方式从缓冲区读取,这意味着首先读取最旧的数据。我们使用缓冲区在两点(例如生产者和消费者)之间存储和传输数据。

其大致结构如图:

循环缓冲区有一个指针指向缓冲区的下一个空位置,并且我们随着每个新条目递增该指针。这意味着当缓冲区已满时,我们添加一个新元素,它会覆盖最旧的元素。这可以确保缓冲区不会溢出,并且新数据不会覆盖重要数据。当缓冲区已满时,循环缓冲区不需要移动元素来为新数据腾出空间。

相反,当缓冲区已满时,新数据将覆盖最旧的数据。将元素添加到循环缓冲区的时间复杂度是常数 O(1)。这使得它在我们必须快速添加和删除数据的实时系统中非常高效。

2.2、结构刨析

循环缓冲区有两个指针,一个指向缓冲区的头部(head),另一个指向缓冲区的尾部(tail)。头指针指向我们将插入下一个元素的位置,尾指针指向缓冲区中最旧元素的位置。

当头指针和尾指针相遇时,我们认为缓冲区已满。实现循环缓冲区的一种方法是使用带有模运算符的数组,当到达数组末尾时进行回绕:

2.3、优点

  1. 节省内存:环形缓冲区可以循环使用,因此不需要一直分配固定大小的内存空间。当缓冲区已满时,新的数据将覆盖最早的数据,从而减少了内存的占用。这对于处理大量数据或者有限的内存资源非常重要。
  2. 高性能:环形缓冲区可以提高数据读取和写入的效率。由于数据在缓冲区中是循环存储的,读/写指针只需要不断移动,而不需要频繁地分配和释放内存。这使得环形缓冲区非常适合处理高速数据流,例如网络传输或实时数据处理。
  3. 适用于并发场景:环形缓冲区可以支持多个读者和写者同时访问。当多个线程需要同时读取或写入数据时,可以通过互斥锁或其他同步机制来确保数据的正确性和一致性。这使得环形缓冲区非常适合并发处理和多线程编程。

2.4、缺点

  1. 数据覆盖:当缓冲区已满时,新的数据将覆盖最早的数据,这可能导致数据丢失或重要信息被覆盖。在某些应用场景下,这种数据覆盖可能会导致问题,需要特别注意。
  2. 数据不一致:由于环形缓冲区的特性,数据的读取和写入是循环进行的,这可能会导致数据的不一致性。例如,当多个线程同时读取和写入数据时,可能会出现数据冲突或数据错乱的情况。
  3. 难以扩展:环形缓冲区的容量是固定的,无法动态扩展。当缓冲区已满时,如果需要处理更多的数据,必须重新分配更大的内存空间,这可能会导致性能下降或内存占用增加的问题。
  4. 指针管理复杂:由于环形缓冲区的特殊性质,读/写指针需要特殊管理,以确保数据的正确性和一致性。这可能会增加代码的复杂度,并引入潜在的错误风险。
  5. 并发控制开销:在多线程环境下,环形缓冲区需要使用同步机制(如互斥锁)来保护数据的读取和写入操作。这可能会导致并发控制开销增加,并可能降低系统的性能。

3、如何使用

3.1、定义一个环形缓冲区

/**
 * @author Shamee loop
 * @date 2023/7/11
 */
public class CircularBuffer {
    private int[] buffer;
    // 头部指针
    private int head;
    // 尾部指针
    private int tail;
    private int size;
    // 初始容量
    private int capacity;

    public CircularBuffer(int capacity) {
        this.capacity = capacity;
        buffer = new int[capacity];
        head = 0;
        tail = 0;
        size = 0;
    }

    /**
     * 向缓冲区中添加数据,如果满了则覆盖
     * @param value
     */
    public synchronized void push(int value) {
        if (size == capacity) {
            // 缓冲区已满,覆盖最早的数据
            head = (head + 1) % capacity;
        }
        buffer[tail] = value;
        tail = (tail + 1) % capacity;
        size++;
    }


    /**
     * 向缓冲区中弹出数据,如果空了,则抛出异常
     * @return
     */
    public synchronized int pop() {
        if (size == 0) {
            throw new NoSuchElementException("Buffer is empty");
        }
        int value = buffer[head];
        head = (head + 1) % capacity;
        size--;
        return value;
    }

    /**
     * 获取缓冲区中第一个数据,但不会弹出数据
     * @return
     */
    public synchronized int peek() {
        if (size == 0) {
            throw new NoSuchElementException("Buffer is empty");
        }
        return buffer[head];
    }

    /**
     * 判断缓冲区是否空了
     * @return
     */
    public synchronized boolean isEmpty() {
        return size == 0;
    }

    /**
     * 判断缓冲区是否满了
     * @return
     */
    public synchronized boolean isFull() {
        return size == capacity;
    }
}

3.2、Demo使用

public static void main(String[] args) {
    CircularBuffer buffer = new CircularBuffer(5);
    for (int i = 0; i < 10; i++) {
        buffer.push(i);
    }
    for (int i = 0; i < 10; i++) {
        int value = buffer.pop();
        System.out.println("Received value: " + value);
    }
}

输出结果:

因为我们定义的容量为5,因此往里面push10个值的时候,后面的新值会把前面的值覆盖,所以我们看到输出结果一直都是5、6、7、8、9。且多次读取,循环缓冲区是重复使用的。

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

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

相关文章

安科瑞智能母线监控在数据中心的应用

引言&#xff1a; 近年来&#xff0c;随着母线槽在建筑及工厂的配电中越来越广泛&#xff0c;母线槽场景运用的越多&#xff0c;随着数据中心建设的快速发展和更高需求&#xff0c;智能母线系统逐渐被应用于机房的末端配电中&#xff0c;具有电流小、插接方便、智能化程度高等…

一百二十八、Kettle——从Hive增量导入到ClickHouse

一、目标 用Kettle把Hive的DWS层数据增量导入到ClickHouse中 工具版本&#xff1a;Kettle&#xff1a;8.2 Hive:3.1.2 ClickHouse21.9.5.16 全量导入请访问拙作链接 http://t.csdn.cn/Rqvuvhttp://t.csdn.cn/Rqvuv 二、前提准备 &#xff08;一&#xff09;kettl…

如何在 .NET Core 中使用 Azure Key Vaul

Azure Key Vault是一个安全可靠的存储库&#xff0c;用于存储在.NET Core应用程序中使用的令牌、密钥、密码、证书和其他敏感数据。接下来我们讲讲如何在C#中使用它。 在构建.NET Core应用程序时&#xff0c;我们经常使用各种“秘密”&#xff0c;如客户端ID、访问令牌、密码、…

我的第一个java项目

安装了idea软件且本地通过cmd 命令启动了mysql。还安装了java sdk。 总结spring-boot通过resource下的mapping文件下的文件xml语法来增删查改(因为使用了MyBatis&#xff0c;MyBatis 的真正强大在于它的语句映射&#xff0c;这是它的魔力所在。由于它的异常强大&#xff0c;映…

7.12 模型显存/mix-precision

一、完全参考&#xff1a;模型的显存和参数量计算 显存占用模型显存(参数)batch_size每个样本显存(输出和梯度动量) 首先是“运算量”和“参数量”两个概念&#xff1a;参数量&#xff1a;这个比较好理解&#xff0c;例如卷积层中的卷积核c_i*k*k*n_o&#xff0c;其参数量就是相…

CAN转EtherNet/IP网关ethernet/ip协议

JM-EIP-CAN 是自主研发的一款 ETHERNET/IP 从站功能的通讯网关。该产品主要功能是将各种 CAN 总线和 ETHERNET/IP 网络连接起来。 本网关连接到 ETHERNET/IP 总线中做为从站使用&#xff0c;连接到 CAN 总线中根据节点号进行读写。 技术参数 ETHERNET/IP 技术参数 网关做为 E…

【计算机网络】第三章 数据链路层(集线器与交换机)

文章目录 第三章 数据链路层3.8 集线器与交换机总结 第三章 数据链路层 3.8 集线器与交换机 使用 集线器HUB 的以太网在逻辑上仍是一个总线网&#xff0c;各站共享总线资源&#xff0c;使用的还是 CSMA/CD 协议&#xff08;半双工&#xff09;。集线器 只工作在物理层&#xff…

UG\NX二次开发 返回视图中的可见对象UF_VIEW_ask_visible_objects

文章作者:里海 来源网站:https://blog.csdn.net/WangPaiFeiXingYuan 简介: 返回视图中的可见对象UF_VIEW_ask_visible_objects 效果: 代码: #include "me.hpp" using namespace std; //获取view视图的可见对象 //view = NULL_TAG 当前视图 vector<tag_t>…

Python endswith()函数使用详解

「作者主页」&#xff1a;士别三日wyx 「作者简介」&#xff1a;CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」&#xff1a;小白零基础《Python入门到精通》 endswith函数使用详解 1、指定范围2、str可以传入元组3、空字符串为真4、大小写敏…

STM32L+BC20+MQTT协议传输温湿度,GPS数据到阿里云物联网平台

&#xff08;阿里云&#xff09;STM32LBC20MQTT协议传输温湿度&#xff0c;GPS数据到阿里云物联网 1、材料准备 准备以下材料 2、设备连接 2.1 插入物联网卡 首先把BC20核心板从开发板上拆下来 然后将物联卡放置在BC20核心板内 物联卡放置完成将BC20核心板重新插入到开发板…

飞控仿真软件

飞控仿真是一种在计算机模拟环境中对飞行控制系统进行测试和验证的方法。它通过使用仿真软件和工具来模拟飞行器的物理行为、传感器数据和控制算法的执行&#xff0c;以评估飞行控制系统的性能和稳定性。 原理 物理模型&#xff1a;仿真软件使用物理模型来描述飞行器的运动行为…

成为一名网络安全工程师难吗?

如果对该专业感兴趣且愿意为之努力&#xff0c;那么学起来是十分轻松的&#xff1b;如果不感兴趣且不愿下功夫&#xff0c;学习起来肯定比较难的 需要学什么&#xff1f; 成为网络安全工程师&#xff0c;需要经历3各阶段&#xff1a;初级安全工程师→中级安全工程师→高级安全…

【Linux后端服务器开发】socket套接字

目录 一、socket 套接字概述 二、socket 函数接口 三、IP地址与端口号的网络格式 四、TCP协议的本地通信C语言示例 一、socket 套接字概述 socket 是什么&#xff1f; socket 本质上是一个抽象的概念&#xff0c;它是一组用于网络通信的 API&#xff0c;提供了一种统一的…

宝塔部署前后端分离项目

✅作者简介&#xff1a;大家好&#xff0c;我是Cisyam&#xff0c;热爱Java后端开发者&#xff0c;一个想要与大家共同进步的男人&#x1f609;&#x1f609; &#x1f34e;个人主页&#xff1a;Cisyam-Shark的博客 &#x1f49e;当前专栏&#xff1a; 项目部署 ✨特色专栏&…

【数据结构导论】第 5 章:图

目录 一、图的基本概念 &#xff08;1&#xff09;图的定义 &#xff08;2&#xff09;图的基本术语 &#xff08;3&#xff09;图的基本运算 二、图的存储结构 &#xff08;1&#xff09;邻接矩阵 ① 图的邻接矩阵 ② 带权图(网)的邻接矩阵 ③ 邻接矩阵的类型定…

【UE4】在控件蓝图上播放视频

UE版本&#xff1a;4.26 在上一篇文章中&#xff08;【UE】场景内播放视频、音频&#xff09;介绍了如何在场景中播放视频&#xff0c;本篇文章将介绍如何在UI上播放视频 效果 步骤 1. 首先在“Content”文件夹中新建一个名为“Movies”的文件夹 2. 在文件夹中随便添加一个.…

iManager for K8S 站点定制(以MongoDB为例)

作者&#xff1a;ls 目录 背景前期准备实现效果实现过程附录YAML中的属性配置占位符列表 背景 SuperMap iManager支持一键创建用户定制的站点&#xff0c;可将已添加的站点模板创建为站点环境&#xff0c;并通过站点使用应用。   定制站点与其他站点相同&#xff0c;在监管方…

学习PostgreSQL的优势

学习 PostgreSQL 可以为您打开许多就业机会。 PostgreSQL 是一种强大的关系型数据库管理系统&#xff0c;被广泛用于企业和组织中的数据管理和应用程序开发。 以下是一些学习 PostgreSQL 可能帮助您找到的工作领域&#xff1a; **1.数据库管理员&#xff1a;**作为 PostgreSQ…

负载均衡详解

负载均衡可以简单分为服务端负载均衡和客户端负载均衡这两种。 根据 OSI 模型&#xff0c;服务端负载均衡还可以分为&#xff1a; 二层负载均衡三层负载均衡四层负载均衡七层负载均衡 最常见的是四层和七层负载均衡 四层负载均衡 工作在 OSI 模型第四层&#xff0c;也就是传…

TIA博途中FC或FB块被多次调用后,监控单个块执行情况的具体方法

TIA博途中FC或FB块被多次调用后,监控单个块执行情况的具体方法 本文以简单的电机启保停程序为例进行说明: 如下图所示,首先添加一个“启保停”FC块,定义块的接口变量,并编写梯形图程序, 如下图所示,在PLC数据类型中添加一个motorControl数据类型,其中包含start、stop…