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.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.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:本人水平有限,如果错漏还请大家帮忙...