C#中lock用法详解
作者:shichen2014 发布时间:2021-06-07 23:24:05
本文实例讲述了C#中lock的用法。分享给大家供大家参考。具体分析如下:
lock 关键字可以用来确保代码块完成运行,而不会被其他线程中断。这是通过在代码块运行期间为给定对象获取互斥锁来实现的。
先来看看执行过程,代码示例如下:
lock 语句用于获取某个给定对象的互斥锁,执行一个语句,然后释放该锁。
lock-statement:(lock 语句:)
lock(expression) embedded-statement(lock ( 表达式 ) 嵌入语句)
lock 语句的表达式必须表示一个引用类型的值。永远不会为 lock 语句中的表达式执行隐式装箱转换,因此,如果该表达式表示的是一个值类型的值,则会导致一个编译时错误。
下列形式的 lock 语句:
lock (x) ...
(其中 x 是一个引用类型的表达式)完全等效于
system.threading.monitor.enter(x);
try {
...
}
finally {
system.threading.monitor.exit(x);
}
不同的只是:实际执行中 x 只计算一次。
当一个互斥锁已被占用时,在同一线程中执行的代码仍可以获取和释放该锁。但是,在其他线程中执行的代码在该锁被释放前是无法获得它的。
一个类的 system.type 对象可以方便地用来当作关于该类的静态方法的互斥锁。例如:
class cache
{
public static void add(object x) {
lock (typeof(cache)) {
...
}
}
public static void remove(object x) {
lock (typeof(cache)) {
...
}
}
}
假设线程a先执行,线程b稍微慢一点。线程a执行到lock语句,判断obj是否已申请了互斥锁,判断依据是逐个与已存在的锁进行object.referenceequals比较(此处未加证实),如果不存在,则申请一个新的互斥锁,这时线程a进入lock里面了。
这时假设线程b启动了,而线程a还未执行完lock里面的代码。线程b执行到lock语句,检查到obj已经申请了互斥锁,于是等待;直到线程a执行完毕,释放互斥锁,线程b才能申请新的互斥锁并执行lock里面的代码。
接下来说一些该lock什么对象。
为什么不能lock值类型,比如lock(1)呢?lock本质上monitor.enter,monitor.enter会使值类型装箱,每次lock的是装箱后的对象。lock其实是类似编译器的语法糖,因此编译器直接限制住不能lock值类型。
退一万步说,就算能编译器允许你lock(1),但是object.referenceequals(1,1)始终返回false(因为每次装箱后都是不同对象),也就是说每次都会判断成未申请互斥锁,这样在同一时间,别的线程照样能够访问里面的代码,达不到同步的效果。同理lock((object)1)也不行。
那么lock("xxx")字符串呢?msdn上的原话是:
锁定字符串尤其危险,因为字符串被公共语言运行库 (clr)“暂留”。 这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。
通常,最好避免锁定 public 类型或锁定不受应用程序控制的对象实例。例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于对象)也可能导致问题。而且lock(this)只对当前对象有效,如果多个对象之间就达不到同步的效果。
lock(typeof(class))与锁定字符串一样,范围太广了。
某些系统类提供专门用于锁定的成员。例如,array 类型提供 syncroot。许多集合类型也提供 syncroot。
而自定义类推荐用私有的只读静态对象,比如:
private static readonly object obj = new object();
为什么要设置成只读的呢?这时因为如果在lock代码段中改变obj的值,其它线程就畅通无阻了,因为互斥锁的
对象变了,object.referenceequals必然返回false。
希望本文所述对大家的C#程序设计有所帮助。


猜你喜欢
- C#中Directory.GetFiles() 函数的使用C#中Directory.GetFiles(string path , strin
- 生成TAGlogt+Tab键:private static final String TAG = "Extract";生
- Activity类处于android.app包中,继承体系如下:1.java.lang.Object2.android.content.Co
- 本文实例为大家分享了Android实现弹幕效果的具体代码,供大家参考,具体内容如下首先分析一下,他是由三层布局来共同完成的,第一层视频布局,
- 一、项目运行环境配置:Jdk1.8 + Tomcat8.5 + Mysql + HBuilderX(Webstorm也行)+ Eclispe
- 简介在java编写过程中,我们会使用到各种各样的表达式,在使用表达式的过程中,有哪些安全问题需要我们注意的呢?一起来看看吧。注意表达式的返回
- SpringBoot版本2.2.4.RELEASE。【1】SpringBoot接收到请求① springboot接收到一个请求返回json格
- 用Android studio做一个简易计算器,供大家参考,具体内容如下长话短说,先建立一个Android项目;创建完成后打开activit
- 前言:众所周知,大家在很多项目中都会使用到图表,具体表现形式为饼图、折线图、柱状图等,但是网上有很多图表架包都是需要收费的,而Google的
- 在C#中,得益于强大的GC机制,使得我们开发程序变得非常简单,很多时候我们只需要管使用,而并不需要关心什么时候释放资源。但是,GC有的时并不
- 前言终于来到了Maven的插件开发,其实Maven的插件并没有想象的那么难,刚开始讲Maven基础的时候就演示了一下JDK是如何打包的,Ma
- 代码案例一:private void button1_Click(object sender, EventArgs e) &n
- Visual Studio 2019 Vue项目 创建成功后可看到如下结构 Visual Studio 2019配置vue项目具体文件结构如
- 一、题目描述题目实现:运行客户端,连接服务器。二、解题思路首先需要启动上题的ServerSocketFrame服务,这样客户端运行时,才能连
- 引言你在服务端的安全管理使用了 Spring Security,用户登录成功之后,Spring Security 帮你把用户信息保存在 Se
- 昨天有个刚学java的师弟发了个程序给我,说死活编译不过,老是报编码问题,自己试了一下,也出问题了...当我们编辑了一个Java源文件保存时
- 在 Flutter 中使用图片是最基础能力之一。作为春节开工后的第一篇文章,17 做了精心准备,满满的都是干货!本文介绍如何在 Flutte
- 安装 小试记一次使用arthas排查jvm中CPU占用过高问题。这工具 * 爆了 碾压我目前使用的全部JVM工具。curl -O https:/
- logback filter过滤某个类 屏蔽某个类使用logback配置日志文件,有的时候需要我们过滤或者屏蔽掉某个类的日志,便可以通过以下
- JavaFXJavaFX 是一个开源的下一代客户端应用平台,适用于基于Java构建的桌面、移动端和嵌入式系统。 它是许多个人和公司的共同努力