详解 .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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈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 # 抑制科学计数法&#…