写在前面

最近一个月一直在弄文件传输组件,其中用到多线程的技术,但有的地方确实需要只能有一个线程来操作,如何才能保证只有一个线程呢?首先想到的就是锁的概念,最近在我们项目组中听的最多的也是锁谁,如何锁?看到有同事使用lock(this),也有lock(private static object),那就有点困惑了,lock到底锁谁才是最合适的呢?

lock

首先先上官方Msdn的说法

lock 关键字可确保当一个线程位于代码的临界区时,另一个线程不会进入该临界区。 如果其他线程尝试进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
lock 关键字在块的开始处调用 Enter,而在块的结尾处调用 Exit。 ThreadInterruptedException 引发,如果 Interrupt 中断等待输入 lock 语句的线程。
通常,应避免锁定 public 类型,否则实例将超出代码的控制范围。

常见的结构 lock (this)、lock (typeof (MyType)) 和 lock ("myLock") 违反此准则:
如果实例可以被公共访问,将出现 lock (this) 问题。
如果 MyType 可以被公共访问,将出现 lock (typeof (MyType)) 问题。
由于进程中使用同一字符串的任何其他代码都将共享同一个锁,所以出现 lock("myLock") 问题。
最佳做法是定义 private 对象来锁定, 或 private static 对象变量来保护所有实例所共有的数据。
在 lock 语句的正文不能使用 等待 关键字。

Enter指的是Monitor.Enter(获取指定对象上的排他锁。),Exit指的是Monitor.Exit(释放指定对象上的排他锁。)

有上面msdn的解释及Exit方法,可以这样猜测“直到该对象被释放”,”该对象“应该是指锁的对象,对象释放了或者对象改变了,其他的线程才可以进入代码临界区(是不是可以这样来理解?)。

在多线程中,每个线程都有自己的资源,但是代码区是共享的,即每个线程都可以执行相同的函数。这可能带来的问题就是几个线程同时执行一个函数,导致数据的混乱,产生不可预料的结果,因此我们必须避免这种情况的发生。

打个比方,有这样一个情景,很多公司所在的大厦的厕所的蹲位都是小单间型的,也就是一次只能进去一个人,那么为了避免每次进去一个人,那怎么做呢?不就是一个人进去之后顺手把门锁上么?这样你在里面干啥事,外边的人也只能等待你解放完了,才能进入。而蹲位的资源(蹲位,手纸等)是共享的。

最常使用的锁是如下格式的代码段:

private static object objlock = new object();
lock (objlock )
{
//要执行的代码逻辑
}

为什么锁的对象是私有的呢?还是以厕所为例子吧,私有就好比,这把锁只有你能访问到,而且最好这把锁不会因为外力而有所改变,别人访问不到,这样才能保证你进去了,别人就进不去了,如果是公有的,就好比你蹲位小单间的锁不是安装在里面而是安装在外边的,别人想不想进就不是你所能控制的了,这样也不安全。

lock

原文章列举的demo无法说明问题,已将原文章的demo删除,将修改后的demo迁移到这篇文章。

 [C#基础]说说lock到底锁谁?(补充与修改)

上面说的最多的是lock对象,那么它能不能lock值类型?

答案是否定的,如

当然lock(null)也是不行的,如图

虽然编译可以通过,但是运行就会出错。

lock(string)

string也是应用类型,从语法上来说是没有错的。

但是锁定字符串尤其危险,因为字符串被公共语言运行库 (CLR)“暂留”。 这意味着整个程序中任何给定字符串都只有一个实例,就是这同一个对象表示了所有运行的应用程序域的所有线程中的该文本。因此,只要在应用程序进程中的任何位置处具有相同内容的字符串上放置了锁,就将锁定应用程序中该字符串的所有实例。通常,最好避免锁定 public 类型或锁定不受应用程序控制的对象实例。例如,如果该实例可以被公开访问,则 lock(this) 可能会有问题,因为不受控制的代码也可能会锁定该对象。这可能导致死锁,即两个或更多个线程等待释放同一对象。出于同样的原因,锁定公共数据类型(相比于对象)也可能导致问题。而且lock(this)只对当前对象有效,如果多个对象之间就达不到同步的效果。lock(typeof(Class))与锁定字符串一样,范围太广了。

总结

关于lock的介绍就到这里,有下面几点需要注意的地方

1、lock的是引用类型的对象,string类型除外。

2、lock推荐的做法是使用静态的、只读的、私有的对象。

3、保证lock的对象在外部无法修改才有意义,如果lock的对象在外部改变了,对其他线程就会畅通无阻,失去了lock的意义。

参考文章

http://www.cnblogs.com/jintianhu/archive/2010/11/19/1881494.html

https://www.cnblogs.com/wolf-sun/p/4209521.html

C# 说说lock到底锁谁?(1)的更多相关文章

  1. [C#基础]说说lock到底锁谁?

    写在前面 最近一个月一直在弄文件传输组件,其中用到多线程的技术,但有的地方确实需要只能有一个线程来操作,如何才能保证只有一个线程呢?首先想到的就是锁的概念,最近在我们项目组中听的最多的也是锁谁,如何锁 ...

  2. C# 说说lock到底锁谁?(2)

    摘要 今天在园子里面有园友反馈关于[C#基础]说说lock到底锁谁?文章中lock(this)的问题.后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修 ...

  3. [C#基础]说说lock到底锁谁?(补充与修改)

    摘要 今天在园子里面有园友反馈关于[C#基础]说说lock到底锁谁?文章中lock(this)的问题.后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修 ...

  4. 说说lock到底锁谁(II)?

    摘要 今天在园子里面有园友反馈关于[C#基础]说说lock到底锁谁?文章中lock(this)的问题.后来针对文章中的例子,仔细想了一下,确实不准确,才有了这篇文章的补充,已经对文章中的demo进行修 ...

  5. 说说lock到底锁谁(I)?

    写在前面 最近一个月一直在弄文件传输组件,其中用到多线程的技术,但有的地方确实需要只能有一个线程来操作,如何才能保证只有一个线程呢?首先想到的就是锁的概念,最近在我们项目组中听的最多的也是锁谁,如何锁 ...

  6. 说说lock到底要锁谁?

    波安搬... http://www.cnblogs.com/wolf-sun/p/4209521.html ---------------------------------------------- ...

  7. Coarse-Grained lock 粗粒度锁

    用一个锁Lock一组相关的对象 有时,需要按组来修改多个对象. 这样,在需要锁住其中一个的时候,必须连带地将其他的对象都上锁. 为每一个对象都加上一个锁是很繁琐的. 粗粒度锁是覆盖多个对象的单个锁. ...

  8. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

  9. JUC--Callable 以及Lock同步锁

    /** * 一.创建执行线程的方式三:实现Callable接口.相较于实现Runnable接口方式,方法可以有返回值,并且可以抛出异常 * 二.callable 需要FutureTask实现类的支持. ...

随机推荐

  1. 【托业】【全真题库】TEST1-语法题

    TEST01 103. delivery date 交货日期 delivery n.传送,投递; [法](正式)交付; 分娩; 讲演; 104. net revenue 净收入,纯收入 105. re ...

  2. allegro17.2 错误记录

    1.网表导入PCB时出现如下错误::error with pin number 'P11'in device ' lfbga176'::Unable to find pin name in adfnc ...

  3. 136A

    #include <stdio.h> #include <string.h> #define MAXSIZE 110 int main() { int giv[MAXSIZE] ...

  4. Oracle创建新undo表空间最佳实践(包含段检查)

    在处理一则ORA-600 [4194]案例时,参考MOS文档:Step by step to resolve ORA-600 4194 4193 4197 on database crash (文档 ...

  5. 取模性质,快速幂,快速乘,gcd和最小公倍数

    一.取模运算 取模(取余)运算法则: 1. (a+b)%p=(a%p+b%p)%p; 2.(a-b)%p=(a%p-b%p)%p; 3.(a*b)%p=(a%p * b%p)%p; 4.(a^b)%p ...

  6. eclipse 编码改成utf-8

    Eclipse的编码格式是系统默认 修改为utf-8,点击Apply and Close 然后项目的编码格式会统一默认utf-8 当然也可以选择other,改成GBK.

  7. python中pip升级

    第一步: 首先安装python,在百度中搜索python,进入python官网,点击downliad, 下载到本地: 下载好后进行安装,与一般软件安装过程一样.安装过程中要注意勾线Add python ...

  8. hadoop启动namenode日志报这个错,首先说怎么看日志

    hadoop启动namenode日志报这个错,首先说怎么看日志, 启动namenode会有这个,ubuntu: starting namenode, logging to /home/xiaoye/h ...

  9. 【ASP.NET Core】在CentOS上安装.NET Core运行时、部署到CentOS

    第一步:Add the dotnet product feed sudo rpm --import https://packages.microsoft.com/keys/microsoft.asc ...

  10. [PHP] 编写爬虫获取淘宝网上所有的商品分类以及关键属性 销售属性 非关键属性数据

    参考文章地址:https://blog.csdn.net/zhengzizhi/article/details/80716608 http://open.taobao.com/apitools/api ...