为什么不要锁(这),锁定变量最好是只读的

  

来自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=392
GPS平台,网站建设,软件开发,系统运维,找森大网络科技! http://cnsendnet.taobao.com

  

一。为什么要锁,锁了什么?

  

当我们使用线程的时候,效率最高的方式当然是异步,即各个线程同时运行,其间不相互依赖和等待。但当不同的线程都需要访问某个资源的时候,就需要同步机制了,也就是说当对同一个资源进行读写的时候,我们要使该资源在同一时刻只能被一个线程操作,以确保每个操作都是有效即时的,也即保证其操作的原子性.lock是c#中最常用的同步方式,格式为锁(objectA) {codeB}。

  

锁(objectA) {codeB}看似简单,实际上有三个意思,这对于适当地使用它至关重要:

  
      <李> objectA被锁了吗?没有则由我来锁,否则一直等待,直至objectA被释放。   <李>锁以后在执行codeB的期间其他线程不能调用codeB,也不能使用objectA。   <李>执行完codeB之后释放objectA,并且codeB可以被其他线程访问。   
  

二。锁(这)怎么了?

  

我们看一个例子:

  
 <代码>使用系统;
  使用System.Threading;
  
  名称空间Namespace1
  {
  类C1
  {
  私人bool僵局=true;//这个方法用到了锁,我们希望锁的代码在同一时刻只能由一个线程访问
  公共空间LockMe(对象o)
  {
  锁(这)
  {
  而(僵局)
  {
  僵局=(bool) o;
  控制台。WriteLine (Foo:我锁:();
  thread . sleep (500);
  }
  }
  }//所有线程都可以同时访问的方法
  公共空间DoNotLockMe ()
  {
  控制台。WriteLine(“我不锁:)”);
  }
  }
  
  类项目
  {
  staticvoid Main (string [] args)
  {
  C1 C1=新C1 ();//在t1线程中调用LockMe,并将死锁设为真(将出现死锁)
  线程t1=新线程(c1.LockMe);
  t1.Start(真正的);
  thread . sleep (100);//在主线程中锁c1
  锁(c1)
  {//调用没有被锁的方法
  c1.DoNotLockMe ();//调用被锁的方法,并试图将死锁解除
  c1.LockMe(假);
  }
  }
  }
   
  

在t1线程中,LockMe调用了锁(这),也就主要是函数中的c1,这时候在主线程中调用锁(c1)时,必须要等待t1中的锁块执行完毕之后才能访问c1,即所有c1相关的操作都无法完成,于是我们看到连c1.DoNotLockMe()都没有执行。

  

把C1的代码稍作改动:

  
 <代码>类C1
  {
  privatebool僵局=true;
  私人储物柜=新对象();//这个方法用到了锁,我们希望锁的代码在同一时刻只能由一个线程访问
  公共空间LockMe(对象o)
  {
  锁(锁)
  {
  而(僵局)
  {
  僵局=(bool) o;
  控制台。WriteLine (Foo:我锁:();
  thread . sleep (500);
  }
  }
  }//所有线程都可以同时访问的方法
  公共空间DoNotLockMe ()
  {
  控制台。WriteLine(“我不锁:)”);
  }
  }
   
  

这次我们使用一个私有成员作为锁定变量(箱),在LockMe中仅仅锁定这个私有储物柜,而不是整个对象。这时候重新运行程序,可以看到虽然t1出现了死锁,DoNotLockMe()仍然可以由主线程访问;LockMe()依然不能访问,原因是其中锁定的储物柜还没有被t1释放。

  

关键点:

  
      <李>锁(这)的缺点就是在一个线程锁定某对象之后导致整个对象无法被其他线程访问。   <李>锁定的不仅仅是段锁里的代码,锁本身也是线程安全的。   <李>我们应该使用不影响其他操作的私有对象作为柜。   <李>在使用锁的时候,被锁定的对象(柜)一定要是引用类型的,如果是值类型,将导致每次锁的时候都会将该对象装箱为一个新的引用对象(事实上如果使用值类型,c#编译器(3.5.30729.1)在编译时就会给出一个错误)。   
  

肯尼添加   

而对于显示器,发现它的静态方法输入(对象obj)有一个异常类型ArgumentNullException,
执行锁(零对象)处,抛出未处理的异常:系统。ArgumentNullException:值不能为空!
在代码段中修改锁定对象,会出现blance<0的情况,并会抛出异常
私有静态只读的对象obj=新对象();
为什么要设置成只读的呢?这是因为如果在锁代码段中改变obj的值,其它线程就畅通无阻了,因为互斥锁的对象变了,对象。ReferenceEquals必然返回假。
所以把上面的修改成私有静态只读的

  

来自森大科技官方博客
http://www.cnsendblog.com/index.php/?p=392

为什么不要锁(这),锁定变量最好是只读的