当前位置: 首页 > article >正文

并发设计模式之双缓冲系统

双缓冲的本质是 ​​通过空间换时间​​,通过冗余的缓冲区解决生产者和消费者的速度差异问题,同时提升系统的并发性和稳定性。

双缓冲的核心优势

优势具体表现
解耦生产与消费生产者和消费者可以独立工作,无需直接同步。
提高并发性生产者和消费者可以同时操作不同的缓冲区,减少等待时间。
避免数据竞争通过锁和条件变量确保读写操作的原子性。
应对突发流量缓冲区作为临时存储,吸收流量峰值,避免系统过载。

双缓冲的潜在问题
​​内存占用翻倍​​:需要维护两个缓冲区,内存消耗增加。
​​切换开销​​:缓冲区切换时需要加锁和同步,可能引入短暂延迟。
​​数据一致性​​:如果切换时机不当,可能导致数据丢失或重复处理。

public class DoubleBufferSystem {// 主缓冲区和备缓冲区(环形数组)private Buffer primaryBuffer;private Buffer backupBuffer;// 锁和条件变量private final ReentrantLock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();// 异步处理线程池private final ExecutorService processor = Executors.newSingleThreadExecutor();// 状态标志private volatile boolean isPrimaryActive = true;public DoubleBufferSystem(int bufferSize) {this.primaryBuffer = new Buffer(bufferSize);this.backupBuffer = new Buffer(bufferSize);}/*** 将数据写入缓冲区,生产者调用此方法** @param data 要写入缓冲区的数据* @throws InterruptedException 如果线程被中断*/public void produce(int data) throws InterruptedException {// 获取锁lock.lock();try {// 当前活跃缓冲区写满时触发切换// 假如换成if,线程被唤醒后缓冲区仍然是满的,线程会直接往下走写入而不是等待,导致数据丢失或异常while (isPrimaryActive && primaryBuffer.isFull()) {// 当前线程会被挂起(进入等待队列),不会占用 CPU 资源notFull.await();}// 写入当前活跃缓冲区Buffer activeBuffer = isPrimaryActive ? primaryBuffer : backupBuffer;activeBuffer.add(data);// 通知所有等待缓冲区非空的消费者notEmpty.signalAll();} finally {// 释放锁lock.unlock();}}// 异步处理数据,一个无限循环的任务到线程池中执行,直接调用public void startProcessing() {processor.submit(() -> {while (true) {lock.lock();try {// 等待数据就绪// 如果当前活跃缓冲区不为空,则当前线程会被挂起,直到有数据被消费掉(即缓冲区变为空)while (isPrimaryActive && !primaryBuffer.isEmpty()) {notEmpty.await();}// 当前活跃缓冲区为空且处于活动状态时,切换缓冲区if (isPrimaryActive) {isPrimaryActive = false;swapBuffers();// 唤醒所有因缓冲区满而阻塞的生产者线程,可以开始写入了notFull.signalAll();}// 处理备份缓冲区中的数据processBuffer(backupBuffer);} finally {lock.unlock();}}});}// 缓冲区切换核心逻辑private void swapBuffers() {Buffer temp = primaryBuffer;primaryBuffer = backupBuffer;backupBuffer = temp;backupBuffer.clear();  // 清空原备缓冲区}// 模拟磁盘写入(异步)private void processBuffer(Buffer buffer) {while (!buffer.isEmpty()) {int data = buffer.poll();// 批量写入提升IO效率System.out.println("Processing data: " + data);}}// 环形缓冲区实现private static class Buffer {private final int[] data;private int head = 0;private int tail = 0;private final int capacity;Buffer(int capacity) {this.capacity = capacity + 1;  // 环形缓冲区需要额外一个位置区分满/空this.data = new int[capacity + 1];}public boolean isFull() {// [1, 2, 3, _]// head = 0, tail = 3// isFull() => (3 + 1) % 4 == 0 => true// 生产者线程尝试写入第四个元素时,会发现 primaryBuffer.isFull() 为 truereturn (tail + 1) % capacity == head;}public boolean isEmpty() {return head == tail;}public void add(int value) {data[tail] = value;tail = (tail + 1) % capacity;}public int poll() {int value = data[head];head = (head + 1) % capacity;return value;}public void clear() {head = 0;tail = 0;}}
}

优化点:
​​减少锁持有时间​:消费者处理数据时释放锁,避免阻塞生产者。
// 处理数据时无需持有锁
processBatch(batchData);
添加优雅终止机制​:通过标志位控制消费者线程退出。

public class DoubleBufferSystem {private final Buffer primaryBuffer;private final Buffer backupBuffer;private final ReentrantLock lock = new ReentrantLock();private final Condition notFull = lock.newCondition();private final Condition notEmpty = lock.newCondition();private final ExecutorService processor = Executors.newSingleThreadExecutor();private volatile boolean isPrimaryActive = true;private volatile boolean isRunning = true;public DoubleBufferSystem(int bufferSize) {this.primaryBuffer = new Buffer(bufferSize);this.backupBuffer = new Buffer(bufferSize);}public void produce(int data) throws InterruptedException {lock.lock();try {while (isPrimaryActive ? primaryBuffer.isFull() : backupBuffer.isFull()) {notFull.await();}Buffer activeBuffer = isPrimaryActive ? primaryBuffer : backupBuffer;activeBuffer.add(data);notEmpty.signalAll();} finally {lock.unlock();}}public void startProcessing() {processor.submit(() -> {while (isRunning) {List<Integer> batchData = new ArrayList<>();lock.lock();try {while (isPrimaryActive && primaryBuffer.isEmpty()) {notEmpty.await();}// 批量取出数据while (!primaryBuffer.isEmpty()) {batchData.add(primaryBuffer.poll());}// 切换缓冲区isPrimaryActive = !isPrimaryActive;swapBuffers();notFull.signalAll();} finally {lock.unlock();}// 异步处理数据 不用加锁processBatch(batchData);}});}private void processBatch(List<Integer> batchData) {for (int data : batchData) {System.out.println("Processing data: " + data);}}private void swapBuffers() {Buffer temp = primaryBuffer;primaryBuffer.clear();primaryBuffer = backupBuffer;backupBuffer = temp;}public void shutdown() {isRunning = false;processor.shutdown();}
}

相关文章:

并发设计模式之双缓冲系统

双缓冲的本质是 ​​通过空间换时间​​&#xff0c;通过冗余的缓冲区解决生产者和消费者的速度差异问题&#xff0c;同时提升系统的并发性和稳定性。 双缓冲的核心优势 优势具体表现解耦生产与消费生产者和消费者可以独立工作&#xff0c;无需直接同步。提高并发性生产者和消…...

linux sysfs的使用

在Linux内核驱动开发中&#xff0c;device_create_file 和 device_remove_file 用于动态创建/删除设备的 sysfs 属性文件&#xff0c;常用于暴露设备信息或控制参数。以下是完整示例及详细说明&#xff1a; 1. 头文件引入 #include <linux/module.h> #include <linux/…...

【数据结构和算法】3. 排序算法

本文根据 数据结构和算法入门 视频记录 文章目录 1. 排序算法2. 插入排序 Insertion Sort2.1 概念2.2 具体步骤2.3 Java 实现2.4 复杂度分析 3. 快排 QuickSort3.1 概念3.2 具体步骤3.3 Java实现3.4 复杂度分析 4. 归并排序 MergeSort4.1 概念4.2 递归具体步骤4.3 Java实现4.4…...

LintCode第192题-通配符匹配

描述 给定一个字符串 s 和一个字符模式 p &#xff0c;实现一个支持 ? 和 * 的通配符匹配。匹配规则如下&#xff1a; ? 可以匹配任何单个字符。* 可以匹配任意字符串&#xff08;包括空字符串&#xff09;。 两个串完全匹配才算匹配成功。 样例 样例1 输入: "aa&q…...

redis常用的五种数据类型

redis常用的五种数据类型 文档 redis单机安装redis数据类型-位图bitmap 说明 官网操作命令指南页面&#xff1a;https://redis.io/docs/latest/commands/?nameget&groupstring 常用命令 keys *&#xff1a;查看所有键exists k1 k2&#xff1a;键存在个数type k1&…...

Linux 进程与线程间通信方式及应用分析

Linux 进程与线程间通信方式及应用分析 文章目录 Linux 进程与线程间通信方式及应用分析 1. 管道&#xff08;Pipe&#xff09;1.1 匿名管道&#xff08;Anonymous Pipe&#xff09;示例代码&#xff1a;结果&#xff1a; 1.2 命名管道&#xff08;FIFO&#xff09;示例代码&am…...

AI日报 - 2024年04月22日

&#x1f31f; 今日概览(60秒速览) ▎&#x1f916; 模型进展 | Google发布Gemini 2.5 Flash&#xff0c;强调低延迟与成本效益&#xff1b;Kling AI 2.0展示多轴运动视频生成&#xff1b;研究揭示SLM在知识图谱上优于LLM&#xff0c;RLHF在推理提升上存局限。 ▎&#x1f4bc;…...

FreeRTos学习记录--2.内存管理

后续的章节涉及这些内核对象&#xff1a;task、queue、semaphores和event group等。为了让FreeRTOS更容易使用&#xff0c;这些内核对象一般都是动态分配&#xff1a;用到时分配&#xff0c;不使用时释放。使用内存的动态管理功能&#xff0c;简化了程序设计&#xff1a;不再需…...

HAL库(STM32CubeMX)——高级ADC学习、HRTIM(STM32G474RBT6)

系列文章目录 文章目录 系列文章目录前言存在的问题HRTIMcubemx配置前言 对cubemx的ADC的设置进行补充 ADCs_Common_Settings Mode:ADC 模式 Independent mod 独立 ADC 模式,当使用一个 ADC 时是独立模式,使用两个 ADC 时是双模式,在双模式下还有很多细分模式可选 ADC_Se…...

单例模式(线程安全)

1.什么是单例模式 单例模式&#xff08;Singleton Pattern&#xff09;是一种创建型设计模式&#xff0c;旨在确保一个类只有一个实例&#xff0c;并提供一个全局访问点来访问该实例。这种模式涉及到一个单一的类&#xff0c;该类负责创建自己的对象&#xff0c;同时确保只有单…...

FreeRTos学习记录--1.工程创建与源码概述

1.工程创建与源码概述 1.1 工程创建 使用STM32CubeMX&#xff0c;可以手工添加任务、队列、信号量、互斥锁、定时器等等。但是本课程不想严重依赖STM32CubeMX&#xff0c;所以不会使用STM32CubeMX来添加这些对象&#xff0c;而是手写代码来使用这些对象。 使用STM32CubeMX时&…...

基于大模型的血栓性外痔全流程风险预测与治疗管理研究报告

目录 一、引言 1.1 研究背景与目的 1.2 研究意义 二、血栓性外痔概述 2.1 定义与发病机制 2.2 临床表现与诊断方法 2.3 现有治疗手段综述 三、大模型在血栓性外痔预测中的应用原理 3.1 大模型技术简介 3.2 模型构建与训练数据来源 3.3 模型预测血栓性外痔的工作流程…...

进程控制(linux+C/C++)

目录 进程创建 写时拷贝 fork 进程终止 退出码 进程退出三种情况对应退出信号 &#xff1a;退出码&#xff1a; 进程退出方法 进程等待 两种方式 阻塞等待和非阻塞等待 小知识 进程创建 1.在未创建子进程时&#xff0c;父进程页表对于数据权限为读写&#xff0c;对于…...

C++如何处理多线程环境下的异常?如何确保资源在异常情况下也能正确释放

多线程编程的基本概念与挑战 多线程编程的核心思想是将程序的执行划分为多个并行运行的线程&#xff0c;每个线程可以独立处理任务&#xff0c;从而充分利用多核处理器的性能优势。在C中&#xff0c;开发者可以通过std::thread创建线程&#xff0c;并使用同步原语如std::mutex、…...

TensorBoard如何在同一图表中绘制多个线条

1. 使用不同的日志目录 TensorBoard 会根据日志文件所在的目录来区分不同的运行。可以为每次运行指定一个独立的日志目录&#xff0c;TensorBoard 会自动将这些目录中的数据加载并显示为不同的运行。 示例&#xff08;TensorFlow&#xff09;&#xff1a; import tensorflow…...

微软Entra新安全功能引发大规模账户锁定事件

误报触发大规模锁定 多家机构的Windows管理员报告称&#xff0c;微软Entra ID新推出的"MACE"&#xff08;泄露凭证检测应用&#xff09;功能在部署过程中产生大量误报&#xff0c;导致用户账户被大规模锁定。这些警报和锁定始于昨夜&#xff0c;部分管理员认为属于误…...

基于FPGA的一维时间序列idct变换verilog实现,包含testbench和matlab辅助验证程序

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 DCT离散余弦变换 4.2 IDCT逆离散余弦变换 4.3 树结构实现1024点IDCT的原理 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) matlab仿真结果 FPGA仿真结果 由于FP…...

Linux进程5-进程通信常见的几种方式、信号概述及分类、kill函数及命令、语法介绍

目录 1.进程间通信概述 1.1进程通信的主要方式 1.2进程通信的核心对比 2.信号 2.1 信号的概述 2.1.1 信号的概念 2.2信号的核心特性 2.3信号的产生来源 2.4信号的处理流程 2.5关键系统调用与函数 2.6常见信号的分类及说明 2.6.1. 标准信号&#xff08;Standard Sig…...

[架构之美]一键服务管理大师:Ubuntu智能服务停止与清理脚本深度解析

[架构之美]一键服务管理大师&#xff1a;Ubuntu智能服务停止与清理脚本深度解析 服务展示&#xff1a; 运行脚本&#xff1a; 剩余服务&#xff1a; 一、脚本设计背景与核心价值 在Linux服务器运维中&#xff0c;服务管理是日常操作的重要环节。本文介绍的智能服务管理脚本&a…...

C++算法(10):二叉树的高度与深度,(C++代码实战)

引言 在二叉树的相关算法中&#xff0c;高度&#xff08;Height&#xff09;和深度&#xff08;Depth&#xff09;是两个容易混淆的概念。本文通过示例和代码实现&#xff0c;帮助读者清晰区分二者的区别。 定义与区别 属性定义计算方式深度从根节点到该节点的边数根节点深度…...

k8s 基础入门篇之开启 firewalld

前面在部署k8s时&#xff0c;都是直接关闭的防火墙。由于生产环境需要开启防火墙&#xff0c;只能放行一些特定的端口&#xff0c; 简单记录一下过程。 1. firewall 与 iptables 的关系 1.1 防火墙&#xff08;Firewall&#xff09; 定义&#xff1a; 防火墙是网络安全系统&…...

Psychology 101 期末测验(附答案)

欢呼 啦啦啦~啦啦啦~♪(^∇^*) 终于考过啦~ 开心(*^▽^*) 撒花✿✿ヽ(▽)ノ✿ |必须晒下证书: 判卷 记录下判卷,还是错了几道,填空题2道压根填不上。惭愧~ 答案我隐藏了,实在想不出答案的朋友可以留言,不定时回复。 建议还是认认真真的学习~认认真真的考试~,知识就…...

安全协议分析概述

一、概念 安全协议&#xff08;security protocol&#xff09;&#xff0c;又称密码协议。是以密码学为基础的消息交换协议&#xff0c;在网络中提供各种安全服务。&#xff08;为解决网络中的现实问题、满足安全需求&#xff09; 1.1 一些名词 那什么是协议呢&#xff1f; …...

基础学习:(7)nanoGPT 剩下的细节

文章目录 前言3 继续巴拉结构3.1 encode 和 embedding3.2 全局layernorm3.3 lm_head(language modeling) 和 softmax3.4 softmax 和 linear 之间的 temperature和topk3.5 weight tying 前言 在 基础学习&#xff1a;&#xff08;6&#xff09;中, 在运行和训练代码基础上,向代…...

【HDFS】verifyEC命令校验EC数据正确性

verifyEC命令是HDFS里用于验证EC文件正确性的一个工具。这是一个非常实用的工具,能帮助我们确定EC的数据内容是否正确,并且如果不正确的话,还有可能会触发reportBadBlock给NN,让NN进行块的重构。 本文先介绍一下verifyEC命令的使用方法,再描述其实现原理细节。 一、命令…...

YOLO11改进,尺度动态损失函数Scale-based Dynamic Loss,减少标签不准确对损失函数稳定性的影响

在目标检测领域,标签噪声与尺度敏感问题始终是制约模型性能提升的"阿喀琉斯之踵"。2025年CVPR最佳论文提出的尺度动态损失函数(Scale-based Dynamic Loss, SDL),通过构建自适应损失调节机制,不仅实现了对YOLOv11检测精度的指数级提升,更重新定义了损失函数的设…...

Spark-SQL连接Hive总结及实验

一、核心模式与配置要点 1. 内嵌Hive 无需额外配置&#xff0c;直接使用&#xff0c;但生产环境中几乎不使用。 2. 外部Hive&#xff08;spark-shell连接&#xff09; 配置文件&#xff1a;将hive-site.xml&#xff08;修改数据库连接为node01&#xff09;、core-site.xml、…...

ROS 2的跨平台优势:国产芯片与Ubuntu系统的深度协同

一、国产硬件全场景适配&#xff1a;从教育到工业的ROS 2革命 瑞芯微三剑客性能解析 芯片架构特性ROS 2优化方案典型延迟/算力RK3399双核A72四核A53启用rmw_fastrtps内存池隔离通信延迟≤1.5msRK3588四核A766TOPS NPUrknn_ros2中间件实现算法热加载目标检测15ms4KRK3576六核A…...

Linux Wlan-四次握手(eapol)框架流程

协议基础 基于 IEEE 802.1X 标准实现的协议 抓包基础 使用上一章文章的TPLINK wn722n v1网卡在2.4G 频段抓包&#xff08;v2、v3是不支持混杂模式的&#xff09; eapol的四个交互流程 根据不同的认证模式不同&#xff0c;两者的Auth流程有所不同&#xff0c;但是握手流程基…...

web组件和http协议

1.web组件 2.自定义元素 3.影子DOM 4.HTML模板 5.http协议 6.tcp ip协议...