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

c# lock关键字的本质

是调用Monitor.Enter(object obj)并且在finally的时候调用Monitor.Exit(obj)

 

在obj是不同数据类型的时候会出现不同的情况

1.锁定类型 例如lock(typeof(int))  lock(typeof(ClassA))   // CalssA 是一个类的定义

  备注:前者作用范围跨AppDomain 不跨Process, 后者不跨AppDomain(默认设置)

  使用范围:绝不推荐使用

2.锁定字符串 例如lock("abc") 和lock(s)//s是一个字符串的实例变量

  备注:当字符串已经驻留在内存的时候 这个lock是有效的, 如果字符串未驻留在内存那么这个lock就失效了,该lock是跨Appdomain不跨Process

  使用范围: 一般不推荐使用

  以下代码显示了非驻留字符串导致的无法lock的问题,请在实际应用中避免lock(a+b)即使他们的值一样 (vs2008 Debug)

 

 

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
class Program
{
staticvoid Main(string[] args)
{
string s1 ="a";
string s2 ="bc";

ThreadPool.QueueUserWorkItem(p
=>
{
Thread.Sleep(
3000); Console.WriteLine(" Thread2 Begin Test");
lock (s1 + s2)
{
Console.WriteLine(
"Thread2 Begin Lock");
Thread.Sleep(
1000);
Console.WriteLine(
"Thread2 End Lock");
}
});
Console.WriteLine(
"Thread1 Begin Test");
lock (s1 + s2)
{
Console.WriteLine(
"Thread1 Begin Lock");
Thread.Sleep(
10000);
Console.WriteLine(
"Thread1 End Lock");
}
}
}
}

 

3.所有继承于System.MarshalByRefObject 的对象  ,例如Remoting Service之类的

  备注:锁定的是代理对象,在远端的对象并没有被锁定(byValue 和byRef 两种类型传数据也有影响)

  使用范围:不推荐

4.值类型, 由于众所周知的装箱的问题...实际上锁定根本不生效

  使用范围:不推荐

5. 应用[MethodImpl(MethodImplOptions.Synchronized)]标记的类

  实例方法锁定的是this   lock(this)

  静态方法锁定的是typeof(ClassName)   lock(typeof(ClassName)) //ClassName是你当前的类名

  使用范围:不推荐, 调用静态方法将导致锁定类型, 实例方法之间也相互影响锁定关系

6.lock(this)

  很容易误用,例如在web page上调用 lock(this)....由于asp.net会为每次httpRequest , new一个类的实例...所以lock(this)在这里一点作用都没有

  在其他的情况下:lock(this)锁定了本身,那么但其他外部对象试图使用这个类的时候会有困扰

  如果你的类是public给其他人用的,那么最好不要lock(this)

  请参考以下代码(不推荐使用)

  

代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace ConsoleApplication1
{
publicclass ClassA
{
publicvoid Test()
{
lock (this)
{
Console.WriteLine(
"Test Begin Lock");
Thread.Sleep(
10000);
Console.WriteLine(
"Test End Lock");
}
}
}
class Program
{
staticvoid Main(string[] args)
{
ClassA classA
=new ClassA();

ThreadPool.QueueUserWorkItem(p
=>
{
Thread.Sleep(
3000); Console.WriteLine(" Thread2 Begin Test");
lock (classA)
{
Console.WriteLine(
"Thread2 Begin Lock");
Thread.Sleep(
1000);
Console.WriteLine(
"Thread2 End Lock");
}
});
classA.Test();
Console.ReadLine();
}
}
}

7. lock(null) 必然抛出一个异常

8.推荐使用以下方法lock

  private static object asyncLock=new object();

  lock(asyncLock)

  使用 private object asyncLock=new object(); 也是ok的,但是请注意避免之前提到的WebPage每次new一个类导致lock失效的问题

  影响范围不跨AppDomain

 

 

  PS1:关于跨不跨AppDomain的问题,其实用处不大,大部分应用程序都只是创建一个DefaultDomain

  PS2:可以将一些Assembly设置为跨AppDomain的,以减少内存浪费和提高性能, 例如string和一些基本类型都是这样实现的

  PS3:本人水平有限,如果错漏还请大家帮忙...

posted @ 2015-11-04 15:40  Cat Qi  阅读(4658)  评论(0编辑  收藏  举报