.NET中lock的使用方法及注意事项

.NET 多线程 互斥锁lock、互斥锁Monitor 、读写锁ReaderWriteLockSlim、spinLock、Semaphore 线程同步 注意:定义的锁对象应该是 私有的,静态的,只读的,引用类型的对象,这样可以防止外部改变锁对象。注意:定义的锁对象应该是 私有的,静态的,只读的,引用类型的对象,这样可以防止外部改变锁对象。注意:定义的锁对象应该是 私有的,静态的,只读的,引用类型的对象,这样可以防止外部改变锁对象。作用:将会锁住代码块的内容,并阻止其他线程进入该代码块,直到该代码块运行完成,释放该锁。作用:将会锁住代码块的内容,并阻止其他线程进入该代码块,直到该代码块运行完成,释放该锁。问题: 既然读读不互斥,为何还要加读锁。 阅读详情

 lock就是把一段代码定义为临界区,所谓临界区就是同一时刻只能有一个线程来操作临界区的代码,当一个线程位于代码的临界区时,另一个线程不能进入临界区,如果试图进入临界区,则只能一直等待(即被阻止),直到已经进入临界区的线程访问完毕,并释放锁旗标。

其基本使用方式如下:

最经典的例子,莫过于模拟银行5个窗口取钱操作的例子了,5个窗口是5个线程,都要取钱,但是同一刻只能有一个窗口可以进行真正的取钱操作(钱数的数值计算,剩余多少等这些代码必须定义为临界区),其他只有等待,其代码如下:

运算结果:

threads[0].Start()
threads[1].Start()
提款之前余额(Balance before Withdrawal):  100
提款数量(Amount to Withdraw)           : -4
提款之后余额(Balance after Withdrawal) :  96

 

提款之前余额(Balance before Withdrawal):  96
提款数量(Amount to Withdraw)           : -5
提款之后余额(Balance after Withdrawal) :  91

 

提款之前余额(Balance before Withdrawal):  91
提款数量(Amount to Withdraw)           : -4
提款之后余额(Balance after Withdrawal) :  87

 

提款之前余额(Balance before Withdrawal):  87
提款数量(Amount to Withdraw)           : -9
提款之后余额(Balance after Withdrawal) :  78

 

提款之前余额(Balance before Withdrawal):  78
threads[2].Start()
提款数量(Amount to Withdraw)           : -8
提款之后余额(Balance after Withdrawal) :  70

 

提款之前余额(Balance before Withdrawal):  70
提款数量(Amount to Withdraw)           : -6
提款之后余额(Balance after Withdrawal) :  64

提款之前余额(Balance before Withdrawal):  64
提款数量(Amount to Withdraw)           : -1
提款之后余额(Balance after Withdrawal) :  63

 

提款之前余额(Balance before Withdrawal):  63
提款数量(Amount to Withdraw)           : -4
提款之后余额(Balance after Withdrawal) :  59

 

提款之前余额(Balance before Withdrawal):  59
提款数量(Amount to Withdraw)           : -2
提款之后余额(Balance after Withdrawal) :  57

 

提款之前余额(Balance before Withdrawal):  57
提款数量(Amount to Withdraw)           : -1
提款之后余额(Balance after Withdrawal) :  56

 

提款之前余额(Balance before Withdrawal):  56
提款数量(Amount to Withdraw)           : -9
提款之后余额(Balance after Withdrawal) :  47

 

提款之前余额(Balance before Withdrawal):  47
提款数量(Amount to Withdraw)           : -7
提款之后余额(Balance after Withdrawal) :  40

 

提款之前余额(Balance before Withdrawal):  40
提款数量(Amount to Withdraw)           : -5
提款之后余额(Balance after Withdrawal) :  35

 

提款之前余额(Balance before Withdrawal):  35
提款数量(Amount to Withdraw)           : -1
提款之后余额(Balance after Withdrawal) :  34

 

提款之前余额(Balance before Withdrawal):  34
提款数量(Amount to Withdraw)           : -1
提款之后余额(Balance after Withdrawal) :  33

 

提款之前余额(Balance before Withdrawal):  33
提款数量(Amount to Withdraw)           : -2
提款之后余额(Balance after Withdrawal) :  31

 

提款之前余额(Balance before Withdrawal):  31
提款数量(Amount to Withdraw)           : -2
提款之后余额(Balance after Withdrawal) :  29

 

提款之前余额(Balance before Withdrawal):  29
提款数量(Amount to Withdraw)           : -3
提款之后余额(Balance after Withdrawal) :  26

 

提款之前余额(Balance before Withdrawal):  26
提款数量(Amount to Withdraw)           : -3
提款之后余额(Balance after Withdrawal) :  23

 

提款之前余额(Balance before Withdrawal):  23
提款数量(Amount to Withdraw)           : -8
提款之后余额(Balance after Withdrawal) :  15

 

提款之前余额(Balance before Withdrawal):  15
提款数量(Amount to Withdraw)           : -6
提款之后余额(Balance after Withdrawal) :  9

 

提款之前余额(Balance before Withdrawal):  9
提款数量(Amount to Withdraw)           : -9
提款之后余额(Balance after Withdrawal) :  0

threads[3].Start()
threads[4].Start()
请按任意键继续. . .

发现窗口1 threads[1].Start()和窗口2 threads[2].Start()先进行取钱,等窗口3 threads[3].Start()和窗口4 threads[4].Start()去取钱的时候,已经没钱了。

 

使用lock需要注意的地方:

1.lock不能锁定空值
某一对象可以指向Null,但Null是不需要被释放的。(请参考:认识全面的null)
2.lock不能锁定string类型,虽然它也是引用类型的。因为字符串类型被CLR“暂留”
这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。因此,最好锁定不会被暂留的私有或受保护成员。
3.lock锁定的对象是一个程序块的内存边界
4.值类型不能被lock,因为前文标红字的“对象被释放”,值类型不是引用类型的

5.lock就避免锁定public 类型或不受程序控制的对象。
例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于对象)也可能导致问题。
使用lock(this)的时候,类的成员变量的值可能会被不在临界区的方法改值了

如下面的测试:

测试ThreadTest的运行结果:

0
Change the value in locking
1
请按任意键继续. . .

测试ThreadTest2的运行结果:

0
0
Can't change the value in locking
请按任意键继续. . .

发现第一个测试里成员变量i被改值了。

      本想在案例一中lock住this对象,让其他的线程不能操作,可是事情不是像我们想象的那样lock(this)是lock this的意思.this中的属性依然能够被别的线程改变.那我们lock住的是什么?是代码段,是lock后面大括号中代码段,这段代码让多个人执行不不被允许的.那返回头来在看lock(this),this是什么意思呢?可以说this知识这段代码域的标志,看看案例二中Thread2.Thread2就明白了,Thread2中的lock需要等到Thread1种lock释放后才开始运行,释放之前一直处于等待状态,这就是标志的表现.
      好吧,让我们来了解一下,lock这段代码是怎么运行的.lock语句根本使用的就是Monitor.Enter和Monitor.Exit,也就是说lock(this)时执行Monitor.Enter(this),大括号结束时执行Monitor.Exit(this).他的意义在于什么呢,对于任何一个对象来说,他在内存中的第一部分放置的是所有方法的地址,第二部分放着一个索引,他指向CLR中的SyncBlock Cache区域中的一个SyncBlock.什么意思呢?就是说,当你执行Monitor.Enter(Object)时,如果object的索引值为负数,就从SyncBlock Cache中选区一个SyncBlock,将其地址放在object的索引中。这样就完成了以object为标志的锁定,其他的线程想再次进行Monitor.Enter(object)操作,将获得object为正数的索引,然后就等待。直到索引变为负数,即线程使用Monitor.Exit(object)将索引变为负数。
       如果明白了Monitor.Enter的原理,lock当然不再话下.当然lock后括号里面的值不是说把整个对象锁住,而是对他的一个值进行了修改,使别的lock不能锁住他,这才是lock(object)的真面目.

       但在实际使用中Monitor还是不推荐,还是lock好的,Monitor需要加上很多try catch才能保证安全性,但lock却帮我们做了,而且lock看起来更优雅.
       在静态方法中如何使用lock呢,由于我们没有this可用,所以我们使用typeof(this)好了,Type也有相应的方法地址和索引,所以他也是可以来当作lock的标志的.
       但微软不提倡是用public的object或者typeof()或者字符串这样的标志就是因为,如果你的public object在其他的线程中被null并被垃圾收集了,将发生不可预期的错误.

 

参考:

http://blog.youkuaiyun.com/yueue/archive/2007/10/13/1823465.aspx

http://www.cnblogs.com/yangpu/archive/2010/11/12/1875848.html

.Net 锁的介绍 1. **Monitor(互斥锁):** `Monitor` 是.NET中最基本的锁机制之一。6. **AutoResetEvent 和 ManualResetEvent(事件类):** `AutoResetEvent` 和 `ManualResetEvent` 是用于线程间通信的事件类。3. **Semaphore(信号量):** `Semaphore` 允许多个线程同时访问共享资源,但在达到一定数量的线程后会阻塞其他线程。每种锁都有其适用的场景和用法,选择合适的锁取决于您的多线程编程需求和性能考虑。 阅读详情

相关推荐

.NET 9新特性:C#中的Lock对象全面解析

NET 9引入了一个新的Lock对象,旨在提供更灵活、更高效的锁机制。这个新的Lock非阻塞:如果无法立即获取锁,不会阻塞线程,而是返回一个结果。可取消:可以在等待锁的过程中取消操作。超时:可以设置超时时间,防止无限等待。多种锁类型:支持独占锁、共享锁等多种锁类型。Lock。

java专栏 1186

lock原理及使用举例(.net)

我们经常用lock加锁,实现数据操作的安全性,本篇文章将介绍lock的实现原理及几种使用方式。 一.原理 lock的作用是将多线程“单线程化”,从而实现多线程按照顺序执行。lock其实是一个语法糖,编译器会将lock转换成monitor,看一下中间代码便一目了然. 1:c#源码 2:编译后的中间码,编译器根据show方法生成了一个类<>__DisplayClass3_0,在该类中包含了一个b__0方法:如下图 3:b__0方法中的代码如下图,我们看到此处用到了Monitor进行加锁: 二.

差池 3907

零代码实战:基于Coze平台打造测试用例生成AI助手

本文详细介绍了如何利用Coze平台零代码打造测试用例生成AI助手,通过智能体和工作流配置,实现需求文档自动解析与结构化测试用例生成。该方案显著提升测试效率,特别适合敏捷开发中频繁变更的需求场景,帮助测试工程师快速应对挑战。

weixin_42526015的博客 209

NET中的线程锁

在.NET中,线程锁(Thread Locking)是一种重要的同步机制,用于确保多个线程在访问共享资源时不会发生冲突,保证线程安全。线程锁的核心目标是避免数据竞争和不一致的状态,确保在同一时刻只有一个线程能够访问特定的资源或代码块。本文将详细讲解.NET中的线程锁,帮助你理解其工作原理、常见实现方式及注意事项。常见的线程锁有:• 自旋锁:当线程尝试获取锁时,它会重复执行一些简单的指令,直到锁可用...

dotNET跨平台 249

【全开源】旅游系统源码(Uniapp+FastAdmin+ThinkPHP)

通过源码的灵活配置和定制开发,我们可以根据旅游企业的实际需求,快速构建出符合其业务特点的旅游系统。旅游系统源码,作为这一变革的基石,为旅游业的数字化转型提供了强有力的支撑。通过深入研究和应用旅游系统源码,我们能够构建出更加智能、便捷、个性化的旅游服务平台,满足游客日益增长的旅游需求。国际化发展:随着全球化的深入发展,旅游系统源码也将迎来国际化的发展机遇,为国内外游客提供更加便捷、高效的旅游服务。跨界融合:旅游系统源码将与更多领域进行跨界融合,如与交通、餐饮、购物等行业的结合,为游客提供更加丰富的旅游体验。

2401_84413757的博客 2149

Excel数据清洗实战:8个必学函数搞定90%的脏数据问题(附案例)

本文通过一个完整的销售数据清洗案例,详细讲解了如何组合使用TRIM、CLEAN、SUBSTITUTE等8个核心Excel函数,构建自动化清洗流水线,高效解决日常办公中90%的脏数据问题,从而将时间留给更有价值的分析工作。

weixin_29215391的博客 583

【转】.NET中lock的使用方法及注意事项

http://daimajishu.iteye.com/blog/1079107# lock就是把一段代码定义为临界区,所谓临界区就是同一时刻只能有一个线程来操作临界区的代码,当一个线程位于代码的临界区时,另一个线程不能进入临界区,如果试图进入临界区,则只能一直等待(即被阻止),直到已经进入临界区的线程访问完毕,并释放锁旗标。 其基本使用方式如下: class Test { ...

weixin_30300523的博客 134

旋转变压器软件解码simulink仿真

旋转变压器软件解码simulink仿真、电机转速位置测量

qq_31446727的博客 2581

.NET中lock的使用方法及注意事项[转]

标准-->ms官方: http://msdn.microsoft.com/zh-cn/library/c5kehkcz(v=vs.90).aspx A、为什么不要 "lock(this)" ? lock object 并是readonly http://blog.csdn.net/gulijiang2008/article/details/7257422 B、转自:htt...

weixin_34037515的博客 137

FoundationPose实战:从零部署到Demo运行全记录

本文详细记录了FoundationPose从零部署到Demo运行的全过程,包括Ubuntu环境配置、项目部署、依赖安装及常见问题解决方案。特别针对复现过程中的关键步骤如CUDA版本选择、Eigen3安装等提供了实用技巧,帮助开发者高效完成FoundationPose的部署与调试。

weixin_27102543的博客 268

Keil 5安装教程(C51与MDK共存)

目录前言MDK的安装C51的安装安装完成后的验证新建C51工程添加C51程序文件编译测试总结 前言 本篇文章将介绍嵌入式开发工具Keil 5的安装方法,并使MDK(Microcontroller Development Kit,开发stm32时会用到)和C51(51单片机C语言软件开发系统)共存。今后使用Keil 5可同时开发51单片机程序和ARM单片机程序,便于学习与从51到32的过渡。 注: 为防止商业纠纷,本篇文章不涉及文中软件的注册破解,请支持正版。 同时为了便于今后更深入的学习,本文不会介绍软件的

xushu_me的博客 6万+

.NET 同步与异步之锁(Lock、Monitor)(七)

本随笔续接:.NET同步与异步之相关背景知识(六)   在上一篇随笔中已经提到、解决竞争条件的典型方式就是加锁 ,那本篇随笔就重点来说一说.NET提供的最常用的锁 lock关键字 和 Monitor。 一、lock关键字Demo public object thisLock = new object(); private long index; ...

weixin_33850890的博客 788

Unity适配Nintendo Switch平台开发

查看文档、下载SDK,都需要账号登录。

凝遥的笔记本 2102

推荐的版本 lock 语句(C# 参考)

最近在研究.NET分布式缓存代码,正好涉及Lock,看了网上的文章,总结了一些Lock相关的知识,供大家一起学习参考。 一、Lock定义 lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。它可以把一段代码定义为互斥段(critical section),互斥段在一个时刻内只允许一个线程进入执行,而其他线程必须等待。这是通过在代码块运行期间为给定对象获取互斥锁来实现的。 ...

weixin_30851867的博客 71

小论文/大论文必备 | YOLO多模态目标检测、绘制曲线对比图 | 引入多种绘制曲线对比图,包括mAP0.5,mAP0.5:0.95,Loss损失变化的曲线对比

本文通过可视化方法分析YOLO多模态模型的训练过程,对比不同实验的检测精度和损失函数变化。主要内容包括:1)绘制mAP@0.5和mAP@0.5:0.95曲线评估检测精度;2)分析边界框回归损失(box_loss)、分类损失(cls_loss)和分布式损失(dfl_loss)的收敛趋势;3)提供完整的Python代码实现,支持多实验对比,可生成高清曲线图。该方法能直观展示模型训练效果,便于优化策略评估和参数调优。

Ai缝合怪、助力小伙伴高效发论文 261

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

线程同步之Lock对象的使用

第一印象,C#关于线程同步的东西好多,保持了C#一贯的大杂烩和四不象风格(Java/Delphi)。临界区跟Java差不多只不过关键字用lock替代了synchronized,然后又用Moniter的Wait/Pulse取代了Object的Wait/Notify,另外又搞出来几个Event……让人甚是不明了。不管那么多,一个一个来吧。 临界区(Critical Section)  是一段在同一时候只被一个线程进入/执行的代码。为啥要有这个东西?是因为这段代码访问了“临界资源”,而这种资源只能同时被互斥地访问

betsyfeng的专栏 838

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C#中Monitor和Lock以及区别

Monitor对象 1.Monitor.Enter(object)方法是获取锁,Monitor.Exit(object)方法是释放锁,这就是Monitor最常用的两个方法,当然在使用过程中为了避免获取锁之后因为异常,致锁无法释放,所以需要在try{} catch(){}之后的finally{}结构体中释放锁(Monitor.Exit())。 2.Monitor的常用属性和方法: Ent

萌萌的It人 www.itmmd.com 870

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

详解 .net9 内置 Lock 对象,更加现代化和灵活可控的锁对象

本文详细介绍 .NET9 平台提供的内置对象 Lock,实现更加现代化,灵活可控的并发编程,更多信息请阅读文章。

ChaITSimpleLove的博客 1216
上一篇: C#正则表达式笔记整理
下一篇: C#.NET中遍历指定目录下的文件(及所有子目录及子目录里更深层目录里的文件)
aspnet2002web
博客等级 码龄21年 482粉丝 310原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值