為什么需要可重入鎖

在黑馬點評項目實戰中,提到了可重入鎖,然后我想到了是不是不同業務在同一線程內反復獲取同一把鎖。本文來討論一下為什么鎖需要可重入。

一、可重入鎖的核心:“同一線程多次獲取同一把鎖”

??可重入(Reentrant)?? 的字面意思是“允許重新進入”,在鎖的上下文中,特指??同一線程可以多次獲取同一把鎖而不會被阻塞??。這與“不同業務”無直接關聯,而是針對??同一線程內的嵌套調用或遞歸調用??場景設計的。

1. 可重入的典型場景:同一線程的嵌套調用

假設你有一個遞歸方法或嵌套調用的業務邏輯,例如:

public void methodA() {lock.lock(); // 第一次加鎖try {// 業務邏輯1...methodB(); // 調用methodB} finally {lock.unlock(); // 最終釋放鎖(需確保只釋放一次)}
}public void methodB() {lock.lock(); // 嵌套調用,需要再次加鎖try {// 業務邏輯2...} finally {lock.unlock();}
}

如果鎖是??不可重入??的,當methodA獲取鎖后調用methodB時,methodB嘗試再次加鎖會被阻塞(因為鎖已被當前線程持有),導致死鎖。而??可重入鎖??允許同一線程多次加鎖(每次加鎖重入次數+1),直到所有加鎖操作都被釋放(重入次數減至0),從而避免死鎖。

2. 與“不同業務”的區別

這里的“不同業務”并非指不同線程或不同功能模塊,而是??同一線程內的不同代碼路徑??(如遞歸、循環調用)。例如:

  • 電商下單場景中,主線程先校驗庫存(調用checkStock()),再扣減庫存(調用deductStock()),兩個方法都需要同一把鎖。若鎖不可重入,checkStock()加鎖后,deductStock()會因無法獲取鎖而阻塞;可重入鎖則允許checkStock()加鎖后,deductStock()直接獲取已持有的鎖(重入次數+1)。

二、為什么需要可重入鎖?應對復雜業務的“嵌套鎖需求”

可重入鎖的設計主要是為了??簡化復雜業務邏輯中的鎖管理??。在真實業務中,嵌套調用(如方法A調用方法B,兩者都需要同一把鎖)非常常見,若使用不可重入鎖,開發者需手動維護鎖的獲取次數(例如,通過計數器記錄嵌套層級),否則容易因忘記釋放鎖或重復釋放導致死鎖或數據不一致。

1. 不可重入鎖的痛點

假設使用不可重入鎖,開發者需手動處理嵌套調用的鎖邏輯:

public class NonReentrantLockExample {private int lockCount = 0; // 手動維護重入次數private final Object lock = new Object();public void methodA() {synchronized (lock) { // 不可重入鎖,第一次加鎖lockCount++;try {// 業務邏輯...methodB(); // 調用methodB} finally {lockCount--;if (lockCount == 0) {// 手動釋放鎖(僅當重入次數為0時)}}}}public void methodB() {synchronized (lock) { // 不可重入鎖,此處會阻塞!// 業務邏輯...}}
}

這種情況下,methodBsynchronized塊會因無法獲取鎖而永久阻塞,必須通過復雜的計數器邏輯手動管理鎖的釋放,容易出錯。

2. 可重入鎖的簡化

Redisson的可重入鎖通過??自動維護重入次數??解決了這一問題:

  • 當同一線程首次獲取鎖時,重入次數初始化為1;
  • 若同一線程再次獲取同一把鎖(如嵌套調用),重入次數遞增(如2、3...);
  • 釋放鎖時,重入次數遞減,直到次數為0時才真正釋放鎖(通知Redis刪除鎖)。

開發者無需手動維護重入次數,鎖的獲取和釋放邏輯與普通單次加鎖一致,大大降低了復雜度。


三、鎖值(重入次數)的含義:“當前線程持有鎖的次數”

Redisson的可重入鎖在Redis中存儲的鍵值對結構大致如下(通過RedissonLock類的tryLock方法實現的Lua腳本):

-- 鎖的鍵:lockKey(如"lock:user:123")
-- 鎖的值:持有者ID(如線程ID+客戶端ID) + 重入次數(初始為1)
if not redis.call('exists', KEYS[1]) thenredis.call('hset', KEYS[1], ARGV[2], 1) -- 持有者ID -> 重入次數1redis.call('pexpire', KEYS[1], ARGV[1]) -- 設置超時時間return 1
elseif redis.call('hexists', KEYS[1], ARGV[2]) == 1 thenlocal count = redis.call('hincrby', KEYS[1], ARGV[2], 1) -- 重入次數+1redis.call('pexpire', KEYS[1], ARGV[1]) -- 重置超時時間(防止過期)return nil
elsereturn 0
end

其中,??鎖的值(存儲在Redis的Hash結構中)?? 包含兩部分:

  • ??持有者ID??:唯一標識當前持有鎖的線程(如thread:123@client:456,避免不同節點的線程ID沖突);
  • ??重入次數??:當前線程已獲取該鎖的次數(初始為1,每次重入+1,釋放時-1)。
1. 鎖值≠0的含義

當鎖值(重入次數)??大于0??時,說明??當前線程仍持有該鎖??(可能是在嵌套調用中,或尚未釋放所有重入次數)。此時,其他線程嘗試獲取該鎖會被阻塞(直到鎖超時或當前線程釋放)。

2. 鎖值=0的含義

當鎖值??等于0??時,說明當前線程已完全釋放該鎖(所有重入次數已耗盡),Redis會刪除該鎖的鍵,其他線程可以重新競爭獲取。


四、總結:可重入鎖的本質是“同一線程的鎖重用”

Redisson可重入鎖的“可重入”核心是??允許同一線程多次獲取同一把鎖??,解決的是復雜業務中嵌套調用(如遞歸、方法調用鏈)導致的鎖沖突問題。其本質是“同一線程的鎖重用”,而非“不同業務的鎖共享”。

鎖值(重入次數)記錄了當前線程持有鎖的次數,只有當次數減至0時,鎖才真正釋放。這一設計避免了開發者手動維護嵌套鎖的復雜性,是分布式系統中處理復雜業務邏輯的重要工具。

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

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

相關文章

【AI】聯網模式

【AI】聯網模式 文章目錄【AI】聯網模式1. 簡介2. 接入步驟2.1 引入依賴2.2 方法構建2.3 接口構建1. 簡介 在使用聯網模式之前,我們如果問起ai一些最近網絡上流傳的一些東西,它可能并不能準確的給你描述出來,因為它的知識庫更新時間可能停留…

第10篇:實戰驗收篇

🔍 實戰演練:多條件房源查詢 需求描述 查找一套符合以下條件的房子: 預算:2000–3000元區域:天河區戶型:兩房 關鍵詞:多條件查詢 AND BETWEEN LIKE 組合運用🎬 開場白“聽起來不難&a…

深入解析YARN中的FairScheduler與CapacityScheduler:資源分配策略的核心區別

YARN資源調度器概述在Hadoop生態系統中,YARN(Yet Another Resource Negotiator)作為核心資源管理平臺,其架構設計將計算資源管理與作業調度解耦,形成了"全局資源管理器(ResourceManager)節…

基于Seata的微服務分布式事務實戰經驗分享

基于Seata的微服務分布式事務實戰經驗分享 1. 業務場景描述 在電商系統中,用戶下單會涉及多個微服務:訂單服務(Order Service)、庫存服務(Inventory Service)、賬戶服務(Account Service&#x…

Linux庫——庫的制作和原理(2)_庫的原理

文章目錄庫的原理理解目標文件ELF文件讀取ELF的工具——readelfELF從形成到加載的輪廓ELF形成可執行文件ELF可執行的加載理解鏈接與加載靜態鏈接ELF加載和進程地址空間虛擬地址 & 邏輯地址重新理解進程地址空間動態鏈接和動態庫的加載進程如何找到動態庫多個進程之間如何共…

Redis C++客戶端——通用命令

目錄 代碼案例 get和set部分 exists部分 del部分 keys部分 expire部分 type部分 本篇文章主要是通過redis-plus-plus庫使用通用命令。 代碼案例 下面用一個代碼演示&#xff1a; #include <sw/redis/redis.h> #include <iostream> #include <vecto…

手機開啟16k Page Size

我買了一個pixel8的手機&#xff0c;系統是Android16,如下操作都是基于這個手機做的。 https://source.android.com/docs/core/architecture/16kb-page-size/16kb-developer-option?hlzh-cn#use_16kb_toggle 使用 16 KB 切換開關 按照開發者選項文檔中的指示啟用開發者選項。…

VLAN的劃分(基于華為eNSP)

VLAN的劃分 前言&#xff1a;為什么VLAN是現代網絡的“隱形骨架”&#xff1f; 當一臺辦公室電腦發送文件給隔壁工位的同事時&#xff0c;數據如何精準抵達目標而不“打擾”其他設備&#xff1f;當企業財務部的敏感數據在網絡中傳輸時&#xff0c;如何避免被其他部門的設備“窺…

從壓縮到加水印,如何實現一站式圖片處理

當你需要對大量圖片進行相同或相似的操作時&#xff08;例如壓縮、裁剪、調整尺寸、添加水印等&#xff09;&#xff0c;逐個處理會非常耗時。批量處理工具可以一次性處理數百張圖片&#xff0c;大大節省了時間。這是一款極致輕巧的圖片處理利器&#xff0c;體積僅有652KB&…

Pythong高級入門Day5

二、面向對象編程面向對象編程&#xff08;Object-Oriented Programming&#xff0c;簡稱OOP&#xff09;是一種通過組織對象來設計程序的編程方法。Python天生就是面向對象的模塊化編程。1. 初識類和對象示意圖&#xff1a;/-------> BYD E6(京A.88888) 實例&#xff0c;對…

C#其他知識點

接口類---interface什么是接口? 在接口當中一般我們認為接口中的成員都是抽象的。接口一般認為是功能的集合。在接口類當中定義的方法都是抽象象方法。(沒有方法體)接口一般我們認為它是一種標準,一種規范,一種約定。給子類或者是派生類制定規范,規定,標準。當子類繼承了該接口…

Maven 環境配置全攻略:從入門到實戰

一、Maven 簡介 Maven 是一個基于項目對象模型 (POM) 的項目管理工具&#xff0c;它可以通過一小段描述信息來管理項目的構建、報告和文檔。 除了強大的程序構建能力外&#xff0c;Maven 還提供了高級項目管理功能。其默認構建規則具有很高的可重用性&#xff0c;通常只需兩三…

現代 C++ 開發工作流(VSCode / Cursor)

? 推薦的現代 C 開發工作流&#xff08;含 VSCode / Cursor 插件配置&#xff09;&#x1f9f0; 一、環境要求 C 編譯器&#xff08;如 g 或 clang&#xff09;CMake&#xff08;建議 ≥ 3.16&#xff09;clangd&#xff08;建議 ≥ 14&#xff0c;最好用系統包管理器安裝&…

[SAP ABAP] ALV報表練習4

SO銷售訂單明細報表業務目的&#xff1a;根據選擇屏幕的篩選條件&#xff0c;使用ALV報表顯示銷售訂單詳情(Sales Order、Material、現有Qty、已開立數量以及剩余數量等)信息效果展示我們在銷售訂單欄位輸入需要查詢的SO單號&#xff0c;這里我們以SO單號0000000221為例&#x…

《設計模式之禪》筆記摘錄 - 10.裝飾模式

裝飾模式的定義裝飾模式(Decorator Pattern)是一種比較常見的模式&#xff0c;其定義如下&#xff1a;Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending fu…

[AI8051U入門第十步]W5500-客戶端

學習目標: 1、認識W5500模塊 2、驅動W5500靜態獲取ip 3、獲取全球唯一碼作為mac地址 4、拔出網線重插網線自動獲取IP 5、編寫W5500作為客戶端進行TCP/IP代碼一、W5500介紹 W5500 是一款由韓國 WIZnet 公司推出的高性能 硬件 TCP/IP 嵌入式以太網控制器,專為嵌入式系統設計,…

UNETR++: Delving Into Efficient and Accurate 3D Medical Image Segmentation

摘要得益于Transformer模型的成功&#xff0c;近期研究開始探索其在3D醫學分割任務中的適用性。在Transformer模型中&#xff0c;自注意力機制是核心構建模塊之一&#xff0c;與基于局部卷積的設計相比&#xff0c;它致力于捕捉長距離依賴關系。然而&#xff0c;自注意力操作存…

Kotlin Flow 在 Jetpack Compose 中的正確打開方式:SharedFlow vs StateFlow 與 LaunchedEffect

在 Jetpack Compose 中&#xff0c;Kotlin Flow 是處理異步數據流的核心工具&#xff0c;而 SharedFlow 和 StateFlow 是最常用的兩種 Flow 類型。但很多開發者對它們的適用場景、如何與 LaunchedEffect 配合使用存在困惑。本文將深入探討它們的區別&#xff0c;并給出最佳實踐…

嵌入式——C語言:指針①

一、指針特點1.讓代碼更加簡潔高效2.提供直接訪問內存的操作3.利用指針可以直接操作硬件二、指針概念&#xff08;一&#xff09;地址&#xff1a;為了區分內存中不同字節的編號&#xff08;0到2^16-1&#xff09;&#xff08;二&#xff09;指針&#xff1a;指針就是地址&…

RabbitMQ—HAProxy負載均衡

上篇文章&#xff1a; RabbitMQ—仲裁隊列https://blog.csdn.net/sniper_fandc/article/details/149312579?fromshareblogdetail&sharetypeblogdetail&sharerId149312579&sharereferPC&sharesourcesniper_fandc&sharefromfrom_link 目錄 1 HAProxy安裝…