Redis底層數據結構之深入理解跳表(2)

? ? ? ? 上一篇文章中我們詳細講述了跳表的增添、查找和修改的操作,這篇文章我們來講解一下跳表在多線程并發時的安全問題。在Redis中,除了網絡IO部分和大文件的后臺復制涉及到多線程外,其余任務執行時全部都是單線程,這也就意味著在Redis中不存在跳表的多線程并發問題。但在Java程序開發中,我們可能也會使用到跳表,這時候就不得不考慮如何設計一個并發安全的調表結構。

? ? ? ? JDK中提供了一種支持并發安全的跳表結構ConcerrentSkipListMap可以直接使用。不過這篇文章我們來自己思考一下在設計并發安全的跳表時我們需要考慮哪些內容。

全局讀寫鎖

? ? ? ? 首先對于跳表的操作可以分為讀操作和寫操作兩種。那么最簡單粗暴的方法就是對整個跳表加讀寫鎖。所有的寫操作需要持有寫鎖才可以進行,所有的讀操作可以同時持有多把讀鎖,來實現并發讀取。不過這時候我們來考慮這樣一個問題,對跳表加了全局讀寫鎖,如果一個線程拿到了寫鎖,并且對跳表的操作時間很長,那么后邊所有的寫操作和讀操作都會被阻塞,如果對跳表的大小、存儲數據的大小和每次寫操作的時間進行嚴格限制,全局加讀寫鎖在寫少讀多的場景下還是有一定的可用性的。

? ? ? ? 上面全局加讀寫鎖雖然實現簡單,但是有很大可能會造成線程間的阻塞等待,實用性并不高,而造成阻塞問題的根源是鎖的顆粒度太大了,有沒有一種方法可以將鎖的顆粒度進行細化,這樣就可以同時允許多個線程拿到不同的鎖進行操作,降低線程阻塞的概率。

節點讀寫鎖

? ? ? ? 我們來思考這樣一個問題,當我們對單向鏈表并發操作時,對于寫操作(增加、刪除),其實只需要執行一步操作,就是找到被操作節點的前一個節點,并將其next修改為被操作節點的后一個節點。這就意味著,如果我們在并發環境下對被操作節點的前一個節點進行加鎖操作,就可以保證同一時間只有一個線程對被加鎖節點后的節點進行操作。

? ? ? ? 在對跳表的節點進行加鎖時,我們還需要多考慮一點,由于新加入的節點的高度是隨機的,可能會比當前跳表的高度要高,這個時候我們需要對跳表的頭結點進行加鎖,并修改跳表的最大高度。

? ? ? ? 總的來說,其實我們在細化跳表中鎖的顆粒度到節點上時,需要考慮兩部分。第一是如果新加入的節點高度小于跳表原最大高度,這時就從上至下逐層取到操作節點的左邊界節點的鎖即可;第二是如果新加入的節點高度大于跳表原有最大高度,這時就需要持有跳表的頭結點鎖,然后再進行第一部分的操作。

查詢操作

? ? ? ? 查詢操作的步驟就是從跳表的最高層head節點開始,從上往下逐層遍歷,直到找到key值小于target并且最接近于target的左邊界節點,然后進行層數下降。具體的流程如下圖所示:

增添操作

? ? ? ? 增加操作執行時,如果增加的節點已經存在了,則會更新為新值,如果不存在,則要將其插入跳表中。可以將增加操作分為以下四個步驟:

? ? ? ? ①首先檢查要添加的節點是否存在。

? ? ? ? ②如果存在,則將舊值更新為新值。

? ? ? ? ③如果不存在,則將新節點插入跳表中。

? ? ? ? ④如果要插入節點,并且節點高度比原有跳表要高,則對跳表的高度進行擴容。

? ? ? ? 上述步驟中的①、②、③在并發情況下需要是原子性的,來保證單一線程對跳表更改的有效性。具體的流程如下圖所示:

刪除操作

? ? ? ? 刪除操作的步驟就是查詢到要刪除的節點,將其每一層的前一個節點的指針進行變更,指向當前層被操作節點的后一個節點就可以了。具體的流程如下所示:

? ? ? ? 不過刪除操作存在一個問題,就是左邊界這種策略對于刪除和增添并發執行的時候會失效,可能會造成新增添的節點被誤刪。所以造執行刪除操作時,還是采用全局鎖的方式來對其和增添操作進行隔離。

? ? ? ? 本文主要梳理了一下自己實現并發安全的跳表的一些思路,算是學完Redis底層數據結構和并發編程之后筆者的一些思考,如果有什么問題或者勘誤,歡迎評論區留言。

????????

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/82783.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/82783.shtml
英文地址,請注明出處:http://en.pswp.cn/web/82783.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Go語言依賴管理與版本控制-《Go語言實戰指南》

在現代軟件開發中,項目的第三方依賴和版本控制扮演著至關重要的角色。Go 語言自 Go 1.11 引入 Modules(模塊化管理)以來,已經實現了內建的依賴管理機制,徹底擺脫了傳統 GOPATH 模式的限制。 本章將深入探討如何使用 Go…

Appium+python自動化(十一)- 元素定位- 下

1、 List定位 List顧名思義就是一個列表,在python里面也有list這一個說法,如果你不是很理解什么是list,這里暫且理解為一個數組或者說一個集合。首先一個list是一個集合,那么他的個數也就成了不確定性,所以這里需要用復…

stress 服務器壓力測試的工具學習

一、stress 工具介紹 tress 是一種工具,可以對符合 POSIX 標準的操作系統施加可配置數量的 CPU、內存、I/O 或磁盤壓力,并報告其檢測到的任何錯誤。 stress 不是一個基準測試。它是由系統管理員用來評估其系統擴展性的工具,由內核程序員用來…

不止抓請求:5種開發場景中的抓包組合策略(含 Charles 等工具)

很多開發者用抓包,只在“接口調不通”的時候。 但在復雜項目中,抓包早已不僅是調錯工具,更是開發節奏提速器、協作問題解耦器、架構瓶頸探測器。 關鍵在于——不同場景下,你要用對方法、配對工具。 以下是我根據日常開發實戰&a…

藍橋杯3498 01串的熵

問題描述 對于一個長度為 23333333的 01 串, 如果其信息熵為 11625907.5798&#xff0c; 且 0 出現次數比 1 少, 那么這個 01 串中 0 出現了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚舉 0 出現的次數//因…

計算機系統大作業——程序人生

計算機系統 大作業 題 目 程序人生-Hello’s P2P 專 業 物聯網工程 學   號 2022112820 班 級 2237301 學 生 孟宇航 指 導 教 師 吳 銳 計算機科學與技術學院 2024年…

〈軟件安裝管家軟件目錄〉?Windows系統版

①裝機常用 ?壓縮解壓WinRAR7-ZIPBandZip360壓縮?文件工具EverythingOneCommander XYplorer ReNamer ?卸載軟件CCleanerIObitUninstallerUninstall toolGeekAutodesk卸載Adobe卸載Ashampoo?驅動軟件驅動人生&#xff08;離線版&#xff09;驅動精靈&#xff08;離線版&…

CentOS Stream 8 Unit network.service not found

一、問題現象 在 CentOS Stream 8 操作系統中&#xff0c;配置完靜態IP 信息&#xff0c;想重啟網絡服務。 執行如下命令&#xff1a; systemctl restart network 提示信息如下&#xff1a; Failed to restart network.service: Unit network.service not found. 二、問題…

極空間z4pro配置gitea mysql,內網穿透

極空間z4pro配置gitea mysql等記錄&#xff0c;內網穿透 1、mysql、gitea鏡像下載&#xff0c;極空間不成功&#xff0c;先用自己電腦科學后下載鏡像,拉取代碼&#xff1a; docker pull --platform linux/amd64 gitea/gitea:1.23 docker pull --platform linux/amd64 mysql:5.…

[假面騎士] 龍騎淺談

作為一個偽二次元的我&#xff0c;總感覺目前沒有什么好番可追。結果某一天在小破站刷到了一個假面騎士相關的視頻&#xff0c;我就突發奇想&#xff0c;要不把假面騎士補完算了。 搜了搜&#xff0c;版權全在企鵝哪兒&#xff0c;不想充&#xff0c;于是去找了某盤的資源。果…

F5 GSLB 最佳實踐:如何手動將Wide IP 故障轉移到另一個數據中心

下面簡要介紹如何手動將 Wide IP(用于 DNS 負載均衡)故障轉移到另一個數據中心,并提供一些最佳實踐。假設您使用 F5 BIG-IP DNS(以前稱為 GTM)管理一個 Wide IP,該 IP 引用位于不同數據中心的虛擬服務器 (VIP)。 典型的 GSLB (BIG-IP DNS) 設置 Wide IP:表示您想要全局負…

FART 脫殼某大廠 App + CodeItem 修復 dex + 反編譯還原源碼

版權歸作者所有&#xff0c;如有轉發&#xff0c;請注明文章出處&#xff1a;https://cyrus-studio.github.io/blog/ FART 脫殼 fartthread 方法在 app 啟動的時候&#xff08;ActivityThread&#xff09;開啟 fart 線程&#xff0c;休眠 60 秒&#xff0c;等待 app 啟動完成后…

在maven項目中 繼續增加maven 項目

背景項目 基于若依項目 由于若依項目都是Maven項目有父子結構因此自己建項目 也需如此管理 添加子Maven項目 利用idea 自帶工具 maven archetype 這里選 webapp 骨架 在這里構建自己的項目架子即可 將 這個架子加入到啟動類中

網絡攻防技術十四:入侵檢測與網絡欺騙

文章目錄 一、入侵檢測概述二、入侵系統的分類三、入侵檢測的分析方法1、特征檢測&#xff08;濫用檢測、誤用檢測&#xff09;2、異常檢測 四、Snort入侵檢測系統五、網絡欺詐技術1、蜜罐2、蜜網3、網絡欺騙防御 六、簡答題1. 入侵檢測系統對防火墻的安全彌補作用主要體現在哪…

吳恩達MCP課程(5):mcp_chatbot_prompt_resource.py

前提條件&#xff1a; 1、吳恩達MCP課程&#xff08;5&#xff09;&#xff1a;research_server_prompt_resource.py 2、server_config_prompt_resource.json文件 {"mcpServers": {"filesystem": {"command": "npx","args"…

【Linux】Linux基礎指令3

1. which指令 功能&#xff1a;搜索系統指定的命令 2. whereis指令 功能&#xff1a;?于找到程序的源、?進制?件或?冊 3. grep指令 語法&#xff1a; grep [ 選項 ] 搜尋字符串 ?件 功能&#xff1a;在?件中搜索字符串&#xff0c;將找到的?打印出來 常?選項&…

李沐《動手學深度學習》d2l安裝教程

文章目錄 最新回答報錯提醒安裝對應版本安裝C工具和Windows SDK 最新回答 安裝舊版本即可 pip install d2l0.17.0 WARNING: Ignoring invalid distribution -pencv-python (e:\python3.10\lib\site-packages) Looking in indexes: https://pypi.tuna.tsinghua.edu.cn/simple C…

CMake 為 Debug 版本的庫或可執行文件添加 d 后綴

在使用 CMake 構建項目時,我們經常需要區分 Debug 和 Release 構建版本。一個常見的做法是為 Debug 版本的庫或可執行文件添加后綴(如 d),例如 libmylibd.so 或 myappd.exe。 本文將介紹幾種在 CMake 中實現為 Debug 版本自動添加 d 后綴的方法。 方法一:使用 CMAKE_DEBU…

echarts樹狀圖與vue3

父組件 - 使用RadialTreeView <template><div class"page-container"><div class"header-title">美國產品圖譜 (ECharts Radial Tree)</div><RadialTreeView :chart-data"radialData" background-color"#E6E6F…

C# 日志管理功能代碼

一、功能概述 本應用通過 AsyncFileLogger 類提供了靈活的日志控制功能&#xff0c;可在運行時通過 UI 界面啟用或禁用日志記錄。日志系統具有以下特點&#xff1a; 可控制開關&#xff1a;通過按鈕隨時啟用或禁用日志&#xff0c;無需重啟應用異步寫入&#xff1a;日志記錄采…