詳解 .net9 內置 Lock 對象,更加現代化和靈活可控的鎖對象

.NET 9 引入了全新的 System.Threading.Lock 類型,作為更現代、類型安全且具備遞歸支持的同步原語。與傳統的基于 Monitor.Enter/lock(obj) 的方式不同,Lock 是一個具體的類,提供了更靈活的 API 和結構化編程模型。

  • Lock 類

Lock 是一個具體密封類,詳細代碼如下:

#region 程序集 System.Runtime, Version=9.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// C:\Program Files\dotnet\packs\Microsoft.NETCore.App.Ref\9.0.5\ref\net9.0\System.Runtime.dll
#endregionnamespace System.Threading
{//// 摘要://     Provides a mechanism for achieving mutual exclusion in regions of code between//     different threads.public sealed class Lock{//// 摘要://     Initializes a new instance of the System.Threading.Lock class.public Lock();//// 摘要://     Gets a value that indicates whether the lock is held by the current thread.//// 返回結果://     true if the current thread holds the lock; otherwise, false.public bool IsHeldByCurrentThread { get; }//// 摘要://     Enters the lock, waiting if necessary until the lock can be entered.//// 異常://   T:System.Threading.LockRecursionException://     The lock has reached the limit of repeated entries by the current thread. The//     limit is implementation-defined and is intended to be high enough that it would//     not be reached in normal situations.public void Enter();//// 摘要://     Enters the lock, waiting if necessary until the lock can be entered.//// 返回結果://     A System.Threading.Lock.Scope that can be disposed to exit the lock.//// 異常://   T:System.Threading.LockRecursionException://     The lock has reached the limit of repeated entries by the current thread. The//     limit is implementation-defined and is intended to be high enough that it would//     not be reached in normal situations.public Scope EnterScope();//// 摘要://     Exits the lock.//// 異常://   T:System.Threading.SynchronizationLockException://     The current thread does not hold the lock.public void Exit();//// 摘要://     Tries to enter the lock without waiting.//// 返回結果://     true if the lock was entered by the current thread; otherwise, false.//// 異常://   T:System.Threading.LockRecursionException://     The lock has reached the limit of repeated entries by the current thread. The//     limit is implementation-defined and is intended to be high enough that it would//     not be reached in normal situations.public bool TryEnter();//// 摘要://     Tries to enter the lock, waiting if necessary for the specified number of milliseconds//     until the lock can be entered.//// 參數://   millisecondsTimeout://     The number of milliseconds to wait until the lock can be entered. Specify Timeout.Infinite//     (////     -1////     ) to wait indefinitely, or////     0////     to not wait.//// 返回結果://     true if the lock was entered by the current thread; otherwise, false.//// 異常://   T:System.ArgumentOutOfRangeException://     millisecondsTimeout is less than////     -1////     .////   T:System.Threading.LockRecursionException://     The lock has reached the limit of repeated entries by the current thread. The//     limit is implementation-defined and is intended to be high enough that it would//     not be reached in normal situations.public bool TryEnter(int millisecondsTimeout);//// 摘要://     Tries to enter the lock, waiting if necessary until the lock can be entered or//     until the specified timeout expires.//// 參數://   timeout://     A System.TimeSpan that represents the number of milliseconds to wait until the//     lock can be entered. Specify a value that represents Timeout.Infinite (////     -1////     ) milliseconds to wait indefinitely, or a value that represents////     0////     milliseconds to not wait.//// 返回結果://     true if the lock was entered by the current thread; otherwise, false.//// 異常://   T:System.ArgumentOutOfRangeException://     timeout, after its conversion to an integer millisecond value, represents a value//     that is less than////     -1////     milliseconds or greater than Int32.MaxValue milliseconds.////   T:System.Threading.LockRecursionException://     The lock has reached the limit of repeated entries by the current thread. The//     limit is implementation-defined and is intended to be high enough that it would//     not be reached in normal situations.public bool TryEnter(TimeSpan timeout);//// 摘要://     Represents a System.Threading.Lock that might have been entered.public ref struct Scope{//// 摘要://     Exits the lock if the System.Threading.Lock.Scope represents a lock that was//     entered.//// 異常://   T:System.Threading.SynchronizationLockException://     The System.Threading.Lock.Scope represents a lock that was entered and the current//     thread does not hold the lock.public void Dispose();}}
}

🔒 Lock 對象概述

System.Threading.Lock 是一種 輕量級互斥鎖(Lightweight Mutex,用于控制多線程對共享資源的訪問,確保同一時間只有一個線程可以執行特定代碼段

它適用于需要 顯式管理加鎖和解鎖操作 的場景,比如在 非阻塞編程 中嘗試獲取鎖或使用 超時機制

? 特性

  • 支持遞歸鎖定(默認允許同一個線程多次進入)
  • 提供阻塞、非阻塞和帶超時的獲取方式
  • 使用 Scope 結構實現 RAII 風格的自動釋放
  • 線程親和性強,可判斷當前線程是否持有鎖

RAII (Resource Acquisition Is Initialization) 是一種 C++ 編程范式,其核心思想是 將資源的生命周期綁定到對象的生命周期上,即:

  • 資源的獲取發生在對象構造時;
  • 資源的釋放發生在對象析構時。

.NET 9System.Threading.Lock 中,Scope 是一個 ref struct,通過調用 EnterScope() 方法獲得。它實現了類似 RAII 的模式:

//
// 摘要:
//     Represents a System.Threading.Lock that might have been entered.
public ref struct Scope
{//// 摘要://     Exits the lock if the System.Threading.Lock.Scope represents a lock that was//     entered.//// 異常://   T:System.Threading.SynchronizationLockException://     The System.Threading.Lock.Scope represents a lock that was entered and the current//     thread does not hold the lock.public void Dispose();
}// 使用 EnterScope()
using (var scope = myLock.EnterScope())
{// 執行臨界區代碼
} // 自動調用 scope.Dispose(),進而釋放鎖
解釋 RAII 風格的自動釋放

使用 Scope 結構實現 RAII 風格的自動釋放 這句話的意思是:

  • 當你調用 EnterScope() 獲取一個 Scope 實例時,鎖已經被當前線程持有
  • 將該 Scope 實例放入 using 語句塊中,當代碼塊結束時,會自動調用其 Dispose() 方法
  • Dispose() 方法內部,會調用 Exit() 來釋放鎖;
  • 這樣就實現了 鎖的獲取和釋放與代碼塊的進入和退出嚴格綁定,避免忘記釋放鎖或異常情況下鎖未被釋放的問題。

這種方式提升了代碼的安全性和可讀性,是現代 .NET 推薦使用的同步編程模型。

📌 構造函數

public Lock();

初始化一個新的 Lock 實例。默認情況下,該鎖是可重入的(recursive),即同一個線程可以多次調用 Enter() 而不會死鎖。


🧱 主要方法詳解

1. void Enter()

阻塞當前線程直到成功獲取鎖。

var myLock = new Lock();myLock.Enter(); // 阻塞直到獲取鎖
try {// 訪問共享資源
} finally {myLock.Exit();
}
拋出異常:
  • LockRecursionException: 如果遞歸次數超過限制(極少發生)

2. Scope EnterScope()

嘗試進入鎖,并返回一個 ref struct Scope,用于通過 using 自動釋放鎖。

using (myLock.EnterScope())
{// 安全訪問共享資源
}
// 鎖自動釋放

這是推薦的方式,避免手動調用 Exit() 導致的資源泄漏。


3. void Exit()

釋放鎖。必須由當前持有鎖的線程調用,否則拋出異常。

myLock.Enter();
try {// ...
} finally {myLock.Exit();
}
拋出異常:
  • SynchronizationLockException: 當前線程未持有鎖

4. bool TryEnter()

嘗試立即獲取鎖,不等待。

if (myLock.TryEnter())
{try {// 成功獲取鎖} finally {my7.Exit();}
}
else
{// 獲取失敗,跳過
}

返回值:

  • true: 成功獲取鎖
  • false: 鎖已被其他線程占用

5. bool TryEnter(int millisecondsTimeout)

嘗試在指定時間內獲取鎖。

bool lockTaken = myLock.TryEnter(1000); // 最多等待1秒
if (lockTaken)
{try { /* ... */ } finally { myLock.Exit(); }
}

參數:

  • millisecondsTimeout: 等待毫秒數,-1 表示無限等待,0 表示不等待

返回值:

  • true: 成功獲取鎖
  • false: 超時或未獲取到

6. bool TryEnter(TimeSpan timeout)

同上,但接受 TimeSpan 參數。

bool lockTaken = myLock.TryEnter(TimeSpan.FromSeconds(2));

🧩 嵌套結構:Lock.Scope

這是一個 ref struct,用于封裝鎖的生命周期,推薦配合 using 使用。

using var scope = myLock.EnterScope();
// 執行臨界區代碼

scopedispose 時,會自動調用 Exit()

方法:
public void Dispose();

釋放鎖,若當前線程未持有鎖則拋出異常。


🧠 內部原理簡析

  • Lock 內部基于高效的自旋鎖(SpinLock)+ 內核事件(Event)混合實現。
  • 初期嘗試自旋幾次以快速獲取鎖,失敗后進入內核等待狀態。
  • 支持遞歸鎖定,默認遞歸深度限制較高(足夠日常使用)。
  • 使用線程本地存儲記錄當前線程是否持有鎖,保證 IsHeldByCurrentThread 的準確性。

🔍 屬性:bool IsHeldByCurrentThread

檢查當前線程是否持有該鎖。

if (myLock.IsHeldByCurrentThread)
{Console.WriteLine("當前線程已持有鎖");
}

適用于調試和日志記錄,避免重復加鎖導致死鎖。


🧪 應用場景舉例

場景 1:線程安全的計數器

private int _counter = 0;
private readonly Lock _lock = new();public void Increment()
{using (_lock.EnterScope()){_counter++;}
}public int GetCount()
{using (_lock.EnterScope()){return _counter;}
}

場景 2:線程安全的單例實現

  • 方式一:原生 Lock 實現
public class Singleton
{// 單例實例private static Singleton _instance;// 鎖對象private static readonly Lock _lock = new();// 私有化無參構造函數private Singleton(){// 初始化邏輯}// 獲取單例實例的方法public static Singleton Instance{get{// 先判斷是否已創建,避免每次都加鎖if (_instance == null){using (_lock.EnterScope()){// 再次檢查是否為 null(雙重檢查鎖定)if (_instance == null){_instance = new Singleton();}}}return _instance;}}// 其他方法實現
}
  • 方式二:使用 Lazy<T> & Lock 實現
public class Singleton
{private static readonly Lock _lock = new();private static readonly Lazy<Singleton> _lazyInstance = new(() =>{using (_lock.EnterScope()){return new Singleton();}});// 私有化無參構造函數private Singleton(){// 初始化邏輯}public static Singleton Instance => _lazyInstance.Value;// 其他方法實現
}

場景 3:帶超時的緩存刷新

private readonly Lock _cacheLock = new();
private object _cachedData;public object? GetCachedData()
{if (_cacheLock.TryEnter(TimeSpan.FromSeconds(1))){try{if (_cachedData == null){_cachedData = FetchFromDatabase();}return _cachedData;}finally{_cacheLock.Exit();}}else{// 超時處理邏輯return null;}
}

場景 4:避免跨線程訪問 UI 控件(WinForms)

private readonly Lock _uiLock = new();private void UpdateLabel(string text)
{using (_uiLock.EnterScope()){// 假設 label1 是 WinForm 上的控件if (label1.InvokeRequired){label1.Invoke(new Action(() => label1.Text = text));}else{label1.Text = text;}}
}

?? 注意事項

  • 不要跨線程傳遞 Lock.Scope 實例。
  • 避免在鎖內部進行長時間操作,影響并發性能。
  • 優先使用 EnterScope() + using 來確保鎖釋放。
  • 若需更高性能讀寫分離,請考慮 ReaderWriterLockSlim

🧾 總結

特性描述
類型互斥鎖(Mutex)
是否遞歸是(默認)
是否公平否(先進先出無法保證)
是否托管資源
推薦使用方式EnterScope() + using

System.Threading.Lock.NET 9 中為現代化并發編程設計的新一代同步工具,相比傳統的 lock(obj) 更加靈活可控,適合 高并發、異步、分布式 等復雜場景下的同步需求。

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

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

相關文章

python幾行命令實現快速打包apk

1. ??環境準備? sudo apt update sudo apt install -y python3-pip git zip unzip openjdk-17-jdk sudo apt-get install -y autoconf automake libtool pip install kivy buildozer cython2. ??項目配置? 在項目目錄中初始化Buildozer&#xff1a; buildozer init這會…

實時數倉和離線數倉的區別是什么?企業如何選擇合適的數倉架構?

實時數倉和離線數倉的區別是什么&#xff1f;企業如何選擇合適的數倉架構&#xff1f; 時數倉和離線數倉都是數據倉庫的不同類型&#xff0c;用于存儲和管理企業的數據&#xff0c;但它們在數據處理和使用的時間、速度以及用途方面有明顯的區別。 在介紹實時數倉之前&#xf…

Docker Desktop for Windows 系統設置說明文檔

1. 文檔概述 本文檔旨在詳細說明 Docker Desktop for Windows 應用程序中“設置 (Settings)”界面下的所有可配置選項及其子選項。對于每個配置項&#xff0c;我們將提供其功能描述、推薦配置&#xff08;如適用&#xff09;以及相關注意事項&#xff0c;幫助用戶更好地理解和…

精準監測,健康無憂--XC3576H工控主板賦能亞健康檢測儀

在快節奏的現代生活中&#xff0c;亞健康問題逐漸成為困擾人們健康的隱形殺手。疲勞、失眠、免疫力下降等問題頻發&#xff0c;卻往往因難以察覺而延誤調理。智能亞健康檢測儀通過高科技手段&#xff0c;幫助用戶實時了解身體狀況&#xff0c;提前預警潛在健康風險。 其核心功能…

SBT開源構建工具

SBT 的多元定義與核心解釋 SBT&#xff08;Simple Build Tool&#xff09;是專為 Scala 和 Java 項目設計的開源構建工具&#xff0c;基于 Scala 語言開發&#xff0c;提供依賴管理、編譯、測試、打包等全流程支持。其核心特點包括&#xff1a; 核心功能與特性&#xff1a; …

npm run build后將打包文件夾生成zip壓縮包

安裝依賴 npm install archiver --save-dev準備compress.js文件 const fs require(fs); const archiver require(archiver);const sourceDir ./dist; //替換為你的文件夾路徑 const outputZip ./dist.zip;console.log(開始壓縮); const output fs.createWriteStream(ou…

力扣 215 .數組中的第K個最大元素

文章目錄 題目介紹題解 題目介紹 題解 法一&#xff1a;基于快速排序的選擇方法 以中間元素pivot為基準進行排序后&#xff0c;右指針 r 的位置就是最終全部排序好后pivot的位置&#xff0c;然后去左邊或右邊遞歸尋找第k個位置&#xff08;答案&#xff09;的元素。 代碼如下…

CentOS 7.0重置root密碼

文章目錄 版本&#xff1a;CentOS 7.0內核版本&#xff1a;CentOS Linux, with Linux 3.10.0-123.el7.x86_64 服務器重啟后&#xff0c;等待進入上述頁面&#xff0c;按??鍵&#xff0c;中斷正常啟動。在此頁面按E&#xff0c;進入編輯模式 繼續按?&#xff0c;找到linux16…

Linux之高效文本編輯利器 —— vim

目錄 一、vim的基本概念 二、Vim 的三種基本模式 1. 命令模式&#xff08;Command Mode&#xff09; 2. 插入模式&#xff08;Insert Mode&#xff09; 3. 底行模式&#xff08;Last Line Mode&#xff09; 模式切換方法 IDE例子&#xff1a; 三、vim的基本操作 進入vim…

【STM32】HAL庫 之 CAN 開發指南

基于stm32 f407vet6芯片 使用hal庫開發 can 簡單講解一下can的基礎使用 CubeMX配置 這里打開CAN1 并且設置好波特率和NVIC相關的配置 波特率使用波特率計算器軟件 使用采樣率最高的這段 填入 得到波特率1M bit/s 然后編寫代碼 環形緩沖區 #include "driver_buffer.h&qu…

《Scientific Reports撤稿門技術節分析》——從圖像篡改檢測到學術倫理重建的技術透視

2023年以來&#xff0c;《Scientific Reports》等開放獲取期刊頻繁曝出大規模撤稿事件&#xff0c;涉及數據造假、圖像重復、AI生成內容篡改等技術性學術不端行為。本文以技術視角切入&#xff0c;系統分析撤稿事件背后的技術動因、檢測手段漏洞、學術出版體系的技術短板及應對…

Client請求Grpc服務報錯

現象&#xff1a;err: rpc error: code Unimplemented desc 背景&#xff1a;調用鏈路A->B->C&#xff0c;A是一個Http協議的接口&#xff0c;B也是一個Http協議的接口&#xff0c; 但C是一個Grpc協議的接口。 解決思路&#xff1a;查看C服務對應的proto&#xff0c;比…

機器學習課程設計報告 —— 基于口紅數據集的情感分析

目錄 一、課程設計目的 二、數據預處理及分析 2.1 數據預處理 2.2 數據分析 三、特征選擇 3.1 特征選擇的重要性 3.2 如何進行特征選擇 3.3 特征選擇的依據 3.4 數據集的劃分 四、模型訓練與模型評估 4.1 所有算法模型不調參 4.2 K-近鄰分類模型 4.3 GaussianNB模…

Flutter 實現6個驗收碼輸入框

開箱即用&#xff0c;初始化時就喚起鍵盤&#xff0c;并選中第一個 import package:flutter/material.dart;import dart:async; // 引入 Timer 類class VerificationCode extends StatefulWidget {final String phoneNumber;const VerificationCode({super.key, required this.…

如何查看服務器有幾張GPU

要查看服務器上有多少張 GPU&#xff0c;你可以使用以下幾種方法&#xff1a; 1.1 使用 nvidia-smi工具&#xff08;針對 NVIDIA GPU&#xff09;&#xff1a; 如果你的服務器上安裝了 NVIDIA GPU 驅動程序&#xff0c;那么可以使用 nvidia-smi 命令查看詳細的 GPU 信息。 n…

3099. 哈沙德數

?題目來源&#xff1a; LeetCode題目&#xff1a;3099. 哈沙德數 - 力扣&#xff08;LeetCode&#xff09; 解題思路&#xff1a; 按要求求和判斷即可。 解題代碼&#xff1a; #python3 class Solution:def sumOfTheDigitsOfHarshadNumber(self, x: int) -> int:sumDigi…

數字化回歸本質:第一性原理驅動的制造業轉型與AI+云PLM系統實踐

2014年&#xff0c;埃隆馬斯克在南加州大學商學院的畢業演講上&#xff0c;留下了一場5分鐘的精彩分享&#xff0c;他將自己對工作和人生的思考總結為五個要點&#xff0c;其中一點說到了他的決策方式&#xff1a; “也許你聽我說過&#xff0c;要從物理學的角度思考問題&…

仿DeepSeek AI問答系統完整版(帶RAG本地知識庫+聯網搜索+深度思考) +springboot+vue3

今天教大家如何設計一個企業級的 deepseek問答 一樣的系統 , 基于目前主流的技術&#xff1a;前端vue3&#xff0c;后端springboot。同時還帶來的項目的部署教程。 系統的核心功能 1. 支持本地上傳文檔知識庫&#xff0c;RAG技術。 支持的文檔有txt&#xff0c;doc&#xff0c…

27、請求處理-【源碼分析】-怎么改變默認的_method

27、請求處理-【源碼分析】-怎么改變默認的_method 要改變 Spring Boot 中默認的 _method 參數&#xff0c;可以通過以下步驟實現&#xff1a; #### 原理分析 Spring Boot 中默認的 HiddenHttpMethodFilter 用于將表單中的 _method 參數值映射為實際的 HTTP 方法&#xff08;如…

歐拉角轉為旋轉矩陣

外旋是固定坐標系&#xff0c;內旋是動態坐標系。外旋和內旋具有等價性。 固定坐標系依次繞xyz軸旋轉&#xff0c;旋轉矩陣 動態坐標系依次繞zyx軸旋轉&#xff0c;旋轉矩陣 numpy和scipy計算對比 import numpy as np from numpy import sin, cos, pi # 抑制科學計數法&#…