Redis底层数据结构之深入理解跳表(2)

news2025/6/7 16:08:31

        上一篇文章中我们详细讲述了跳表的增添、查找和修改的操作,这篇文章我们来讲解一下跳表在多线程并发时的安全问题。在Redis中,除了网络IO部分和大文件的后台复制涉及到多线程外,其余任务执行时全部都是单线程,这也就意味着在Redis中不存在跳表的多线程并发问题。但在Java程序开发中,我们可能也会使用到跳表,这时候就不得不考虑如何设计一个并发安全的调表结构。

        JDK中提供了一种支持并发安全的跳表结构ConcerrentSkipListMap可以直接使用。不过这篇文章我们来自己思考一下在设计并发安全的跳表时我们需要考虑哪些内容。

全局读写锁

        首先对于跳表的操作可以分为读操作和写操作两种。那么最简单粗暴的方法就是对整个跳表加读写锁。所有的写操作需要持有写锁才可以进行,所有的读操作可以同时持有多把读锁,来实现并发读取。不过这时候我们来考虑这样一个问题,对跳表加了全局读写锁,如果一个线程拿到了写锁,并且对跳表的操作时间很长,那么后边所有的写操作和读操作都会被阻塞,如果对跳表的大小、存储数据的大小和每次写操作的时间进行严格限制,全局加读写锁在写少读多的场景下还是有一定的可用性的。

        上面全局加读写锁虽然实现简单,但是有很大可能会造成线程间的阻塞等待,实用性并不高,而造成阻塞问题的根源是锁的颗粒度太大了,有没有一种方法可以将锁的颗粒度进行细化,这样就可以同时允许多个线程拿到不同的锁进行操作,降低线程阻塞的概率。

节点读写锁

        我们来思考这样一个问题,当我们对单向链表并发操作时,对于写操作(增加、删除),其实只需要执行一步操作,就是找到被操作节点的前一个节点,并将其next修改为被操作节点的后一个节点。这就意味着,如果我们在并发环境下对被操作节点的前一个节点进行加锁操作,就可以保证同一时间只有一个线程对被加锁节点后的节点进行操作。

        在对跳表的节点进行加锁时,我们还需要多考虑一点,由于新加入的节点的高度是随机的,可能会比当前跳表的高度要高,这个时候我们需要对跳表的头结点进行加锁,并修改跳表的最大高度。

        总的来说,其实我们在细化跳表中锁的颗粒度到节点上时,需要考虑两部分。第一是如果新加入的节点高度小于跳表原最大高度,这时就从上至下逐层取到操作节点的左边界节点的锁即可;第二是如果新加入的节点高度大于跳表原有最大高度,这时就需要持有跳表的头结点锁,然后再进行第一部分的操作。

查询操作

        查询操作的步骤就是从跳表的最高层head节点开始,从上往下逐层遍历,直到找到key值小于target并且最接近于target的左边界节点,然后进行层数下降。具体的流程如下图所示:

增添操作

        增加操作执行时,如果增加的节点已经存在了,则会更新为新值,如果不存在,则要将其插入跳表中。可以将增加操作分为以下四个步骤:

        ①首先检查要添加的节点是否存在。

        ②如果存在,则将旧值更新为新值。

        ③如果不存在,则将新节点插入跳表中。

        ④如果要插入节点,并且节点高度比原有跳表要高,则对跳表的高度进行扩容。

        上述步骤中的①、②、③在并发情况下需要是原子性的,来保证单一线程对跳表更改的有效性。具体的流程如下图所示:

删除操作

        删除操作的步骤就是查询到要删除的节点,将其每一层的前一个节点的指针进行变更,指向当前层被操作节点的后一个节点就可以了。具体的流程如下所示:

        不过删除操作存在一个问题,就是左边界这种策略对于删除和增添并发执行的时候会失效,可能会造成新增添的节点被误删。所以造执行删除操作时,还是采用全局锁的方式来对其和增添操作进行隔离。

        本文主要梳理了一下自己实现并发安全的跳表的一些思路,算是学完Redis底层数据结构和并发编程之后笔者的一些思考,如果有什么问题或者勘误,欢迎评论区留言。

        

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

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

相关文章

[蓝桥杯]兰顿蚂蚁

兰顿蚂蚁 题目描述 兰顿蚂蚁,是于 1986 年,由克里斯兰顿提出来的,属于细胞自动机的一种。 平面上的正方形格子被填上黑色或白色。在其中一格正方形内有一只"蚂蚁"。 蚂蚁的头部朝向为:上下左右其中一方。 蚂蚁的移…

使用 Python 构建并调用 ComfyUI 图像生成 API:完整实战指南

快速打造你自己的本地 AI 图像生成服务,支持 Web 前端一键调用! 📌 前言 在 AIGC 快速发展的今天,ComfyUI 作为一款模块化、节点式的图像生成界面,备受开发者青睐。但默认情况下,ComfyUI 主要通过界面交互…

嵌入式学习笔记-freeRTOS taskENTER_CRITICAL(_FROM_ISR)跟taskEXIT_CRITICAL(_FROM_ISR)函数解析

一 函数taskENTER_CRITICAL,taskEXIT_CRITICAL 函数taskENTER_CRITICAL最终实现如下: 第①处按照系统设定的configMAX_SYSCALL_INTERRUPT_PRIORITY值对中断进行屏蔽 第②处调用一次自增一次 第③处检查中断状态寄存器位,如果有任何中断位置…

1panel面板中部署SpringBoot和Vue前后端分离系统 【图文教程】

1panel面板中部署SpringBoot和Vue前后端分离系统 一,1panel面板部署二,安装OpenResty三,安装MySQL,Redis等Spring boot 运行依赖环境四,SpringBoot 应用配置及打包部署配置打包部署 五 ,前端VUE应用配置打包…

【Android基础回顾】二:handler消息机制

Android 的 Handler 机制 是 Android 应用中实现线程间通信、任务调度、消息分发的核心机制之一,它基于 消息队列(MessageQueue) 消息循环(Looper) 消息处理器(Handler) 组成。 1 handler的使用…

每日Prompt:每天上班的状态

提示词 一个穿着清朝官服的僵尸脸上贴着符纸,在电脑面前办公,房间阴暗,电脑桌面很乱,烟灰缸里面满是烟头

C++11 右值引用:从入门到精通

文章目录 一、引言二、左值和右值(一)概念(二)区别和判断方法 三、左值引用和右值引用(一)左值引用(二)右值引用 四、移动语义(一)概念和必要性(二…

.net 使用MQTT订阅消息

在nuGet下载M2Mqtt V4.3.0版本。(支持.net framework) 订阅主题 public void LoadMQQCData() {string enpoint "xxx.xxx.x.x";//ip地址int port 1883;//端口string user "usrname";//用户名string pwd "pwd";//密码…

【递归、搜索与回溯】综合练习(四)

📝前言说明: 本专栏主要记录本人递归,搜索与回溯算法的学习以及LeetCode刷题记录,按专题划分每题主要记录:(1)本人解法 本人屎山代码;(2)优质解法 优质代码…

强化学习入门:Gym实现CartPole随机智能体

前言 最近想开一个关于强化学习专栏,因为DeepSeek-R1很火,但本人对于LLM连门都没入。因此,只是记录一些类似的读书笔记,内容不深,大多数只是一些概念的东西,数学公式也不会太多,还望读者多多指教…

STM32:CAN总线精髓:特性、电路、帧格式与波形分析详解

声明:此博客是我的学习笔记,所看课程是江协科技的CAN总线课程,知识点都大同小异,我仅进行总结并加上了我自己的理解,所引案例也都是课程中的案例,希望对你的理解有所帮助! 知识点1【CAN总线的概…

贝叶斯深度学习!华科大《Nat. Commun.》发表BNN重大突破!

华科大提出基于贝叶斯深度学习的超分辨率成像,成功被Nat. Commun.收录。可以说,这是贝叶斯神经网络BNN近期最值得关注的成果之一了。另外还有AAAI 2025上的Bella新框架,计算成本降低了99.7%,也非常值得研读。 显然鉴于BNN“不确定…

【大模型LLM学习】Flash-Attention的学习记录

【大模型LLM学习】Flash-Attention的学习记录 0. 前言1. flash-attention原理简述2. 从softmax到online softmax2.1 safe-softmax2.2 3-pass safe softmax2.3 Online softmax2.4 Flash-attention2.5 Flash-attention tiling 0. 前言 Flash Attention可以节约模型训练和推理时间…

物联网数据归档之数据存储方案选择分析

在上一篇文章中《物联网数据归档方案选择分析》中凯哥分析了归档设计的两种方案,并对两种方案进行了对比。这篇文章咱们就来分析分析,归档后数据应该存储在哪里?及存储方案对比。 这里就选择常用的mysql及taos数据库来存储归档后的数据吧。 你在处理设备归档表存储方案时对…

【C语言】C语言经典小游戏:贪吃蛇(上)

文章目录 一、游戏背景及其功能二、Win32 API介绍1、Win32 API2、控制台程序3、定位坐标(COORD)4、获得句柄(GetStdHandle)5、获得光标属性(GetConsoleCursorInfo)1)描述光标属性(CO…

vue2中使用jspdf插件实现页面自定义块pdf下载

pdf下载 实现pdf下载的环境安装jspdf插件在项目中使用 实现pdf下载的环境 项目需求案例背景,点击【pdf下载】按钮,弹出pdf下载弹窗,显示需要下载四个模块的下载进度,下载完成后,关闭弹窗即可! 项目使用的是…

如何防止服务器被用于僵尸网络(Botnet)攻击 ?

防止服务器被用于僵尸网络(Botnet)攻击是关键的网络安全措施之一。僵尸网络是黑客利用大量被感染的计算机、服务器或物联网设备来发起攻击的网络。以下是关于如何防止服务器被用于僵尸网络攻击的技术文章: 防止服务器被用于僵尸网络&#xff…

基于cornerstone3D的dicom影像浏览器 第二十九章 自定义菜单组件

文章目录 前言一、程序结构1. 菜单数据结构2. XMenu.vue3. XSubMenu.vue4. XSubMenuSlot.vue5. XMenuItem.vue 二、调用流程总结 前言 菜单用于组织程序功能,为用户提供导航。是用户与程序交互非常重要的接口。 开源组件库像Element Plus和Ant Design中都提供了功能…

【Block总结】DBlock,结合膨胀空间注意模块(Di-SpAM)和频域模块Gated-FFN|即插即用|CVPR2025

论文信息 标题: DarkIR: Robust Low-Light Image Restoration 作者: Daniel Feijoo, Juan C. Benito, Alvaro Garcia, Marcos Conde 论文链接:https://arxiv.org/pdf/2412.13443 GitHub链接:https://github.com/cidautai/DarkIR 创新点 DarkIR提出了…

口罩佩戴检测算法AI智能分析网关V4工厂/工业等多场景守护公共卫生安全

一、引言​ 在公共卫生安全日益受到重视的当下,口罩佩戴成为预防病毒传播、保障人员健康的重要措施。为了高效、精准地实现对人员口罩佩戴情况的监测,AI智能分析网关V4口罩检测方案应运而生。该方案依托先进的人工智能技术与强大的硬件性能,…