一. 为什么要lock,lock了什么?

 
当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性。lock是C#中最常用的同步方式,格式为lock(objectA){codeB} 。
 
lock(objectA){codeB} 看似简单,实际上有三个意思,这对于适当地使用它至关重要:
1. objectA被lock了吗?没有则由我来lock,否则一直等待,直至objectA被释放。
2. lock以后在执行codeB的期间其他线程不能调用codeB,也不能使用objectA。
3. 执行完codeB之后释放objectA,并且codeB可以被其他线程访问。
 

二. lock(this)怎么了?

 
我们看一个例子:
lock
using System;
using System.Threading; namespace Namespace1
{
    class C1
     {
        privatebool deadlocked= true;         //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
        publicvoid LockMe(object o)
         {
            lock (this)
             {
                while(deadlocked)
                 {
                     deadlocked = (bool)o;
                     Console.WriteLine("Foo: I am locked :(");
                     Thread.Sleep(500);
                 }
             }
         }         //所有线程都可以同时访问的方法
        publicvoid DoNotLockMe()
         {
             Console.WriteLine("I am not locked :)");
         }
     }     class Program
     {
        staticvoid Main(string[] args)
         {
             C1 c1 =new C1();             //在t1线程中调用LockMe,并将deadlock设为true(将出现死锁)
             Thread t1= new Thread(c1.LockMe);
             t1.Start(true);
             Thread.Sleep(100);             //在主线程中lock c1
            lock (c1)
             {
                //调用没有被lock的方法
                 c1.DoNotLockMe();
                //调用被lock的方法,并试图将deadlock解除
                 c1.LockMe(false);
             }
         }
     }
 
在t1线程中,LockMe调用了lock(this), 也就是Main函数中的c1,这时候在主线程中调用lock(c1)时,必须要等待t1中的lock块执行完毕之后才能访问c1,即所有c1相关的操作都无法完成,于是我们看到连c1.DoNotLockMe()都没有执行。
 
把C1的代码稍作改动:
C1
    class C1
     {
        privatebool deadlocked= true;
        privateobject locker= newobject();         //这个方法用到了lock,我们希望lock的代码在同一时刻只能由一个线程访问
        publicvoid LockMe(object o)
         {
            lock (locker)
             {
                while(deadlocked)
                 {
                     deadlocked = (bool)o;
                     Console.WriteLine("Foo: I am locked :(");
                     Thread.Sleep(500);
                 }
             }
         }         //所有线程都可以同时访问的方法
        publicvoid DoNotLockMe()
         {
             Console.WriteLine("I am not locked :)");
         }
     }
这次我们使用一个私有成员作为锁定变量(locker),在LockMe中仅仅锁定这个私有locker,而不是整个对象。这时候重新运行程序,可以看到虽然t1出现了死锁,DoNotLockMe()仍然可以由主线程访问;LockMe()依然不能访问,原因是其中锁定的locker还没有被t1释放。
 
关键点:
1. lock(this)的缺点就是在一个线程锁定某对象之后导致整个对象无法被其他线程访问。
2. 锁定的不仅仅是lock段里的代码,锁本身也是线程安全的。
3. 我们应该使用不影响其他操作的私有对象作为locker。
4. 在使用lock的时候,被lock的对象(locker)一定要是引用类型的,如果是值类型,将导致每次lock的时候都会将该对象装箱为一个新的引用对象(事实上如果使用值类型,C#编译器(3.5.30729.1)在编译时就会给出一个错误)。
 
 
kenny add
 

而对于Monitor,发现它的静态方法Enter(object obj)有一个异常类型ArgumentNullException,

执行lock(null对象 )处,抛出未处理的异常:System.ArgumentNullException: 值不能为空!

在代码段中修改锁定对象,会出现 blance<0的情况,并会抛出异常

private static readonly object obj = new object();

为什么要设置成只读的呢?这是因为如果在lock代码段中改变obj的值,其它线程就畅通无阻了,因为互斥锁的对象变了,object.ReferenceEquals必然返回false。

所以把上面的修改成private static readonly

转自http://blog.csdn.net/gulijiang2008/article/details/7257422

为什么不要 "lock(this)" ? lock object 并是readonly(转载)的更多相关文章

  1. Lock的lock/unlock, condition的await/singal 和 Object的wait/notify 的区别

    在使用Lock之前,我们都使用Object 的wait和notify实现同步的.举例来说,一个producer和consumer,consumer发现没有东西了,等待,produer生成东西了,唤醒. ...

  2. 关于Application.Lock和Lock(obj) 转 http://www.cnblogs.com/yeagen/archive/2012/03/01/2375610.html

    关于Application.Lock和Lock(obj) Posted on 2012-03-01 15:28 billpeng 阅读(3498) 评论(3) 编辑 收藏 1.Application. ...

  3. 关于Application.Lock和Lock(obj)

    http://www.cnblogs.com/yeagen/archive/2012/03/01/2375610.html 1.Application.Lock和Application.UnLock一 ...

  4. Python用上锁和解锁 lock lock.acquire lock.release 模拟抢火车票

    Python用上锁和解锁  lock lock.acquire lock.release 模拟抢火车票 import jsonimport timefrom multiprocessing impor ...

  5. “全栈2019”Java多线程第二十七章:Lock获取lock/释放unlock锁

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  6. [MySQL] gap lock/next-key lock浅析

    当InnoDB在判断行锁是否冲突的时候, 除了最基本的IS/IX/S/X锁的冲突判断意外, InnoDB还将锁细分为如下几种子类型: record lock (RK) 记录锁, 仅仅锁住索引记录的一行 ...

  7. gap lock/next-key lock浅析 Basic-Paxos协议日志同步应用

    http://www.cnblogs.com/renolei/p/4673842.html 当InnoDB在判断行锁是否冲突的时候, 除了最基本的IS/IX/S/X锁的冲突判断意外, InnoDB还将 ...

  8. gap lock/next-key lock浅析Basic-Paxos协议日志同步应用

    http://www.cnblogs.com/renolei/p/4673842.html 当InnoDB在判断行锁是否冲突的时候, 除了最基本的IS/IX/S/X锁的冲突判断意外, InnoDB还将 ...

  9. C# 使用lock关键字lock不同的对象

    c# lock关键字的本质 是调用Monitor.Enter(object obj)并且在finally的时候调用Monitor.Exit(obj) 在obj是不同数据类型的时候会出现不同的情况 1. ...

随机推荐

  1. maven項目創建紅叉

    出现问题的原因: 解决方案: 在pom.xml中配置jdk的版本

  2. BZOJ 5395--[Ynoi2016]谁的梦(STL&容斥)

    5395: [Ynoi2016]谁的梦 Time Limit: 80 Sec  Memory Limit: 128 MBSubmit: 22  Solved: 7[Submit][Status][Di ...

  3. 标准的sql执行顺序

    正常情况下是先join再进行where过滤

  4. bonjour browser 下载

    在Mac 上叫 Bonjour Browser http://www.macupdate.com/app/mac/13388/bonjour-browser/download IOS 上的 app 叫 ...

  5. 使用putty连接本地VirtualBox上的centos7 linux主机

    1. 查看linux主机默认ssh端口 因为是使用ssh连接虚拟机上的linux主机的,所以需要查看centos ssh默认端口,一般是22 打开终端 输入cd /etc/ssh/ 查看ssh_con ...

  6. windows系统上安装与使用Android NDK r5

    windows系统上安装与使用Android NDK r5  很早就听说了android的NDK应用,只是一直没有时间去研究,今天花了点时间在windows平台搭建了NDK环境,并成功运行了第一个简单 ...

  7. 指定nginx某个目录显示目录结构

    1.修改配置文件/usr/local/nginx/conf/nginx.conf 指定目录,开启autoindex为on. location /study { autoindex on; } 2. 保 ...

  8. POJ 1089

    #include <iostream> #include <algorithm> #define MAXN 50005 using namespace std; struct ...

  9. Servlet基础知识点

    一.web.xml 的加载顺序是: ServletContext-> context-param ->listener -> filter -> servlet,而同个类型之间 ...

  10. 【链表】Odd Even Linked List

    题目: Given a singly linked list, group all odd nodes together followed by the even nodes. Please note ...