浅谈c#中使用lock的是与非
1、从“最简单”的单例模式说起:
public class Singleton{
private static Singleton instance = null;
private static readonly object syncRoot = new object();
private Singleton()
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
稍微了解设计模式基础知识的人对上面的代码应该不会陌生。上次去面试,主考官就让楼猪写个单例。虽然平时已经很久没有刻意去使用设计模式编程了,但是对于这个单例模式,咩哈哈,虽然大丈夫喜怒不形于色,但是nc楼猪当时那个意气风发踌躇满志运笔如飞锋芒毕露啊,嘿嘿,中规中矩地交了如上答案。面试官看了一下肯定了两句,话锋一转,问lock那里的object实例可以直接用instance替代吗?new一个object是否多余,可否写成下面的形式:
public class Singleton{
private static Singleton instance = null;
//private static readonly object syncRoot = new object();
private Singleton()
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
lock (instance)//instance能替换syncRoot吗?
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
虽然在这个问题前面,面试官问的一个数据库设计和几个c#的小问题(有一个题楼猪当时竟然嘴硬说那是“奇技淫巧”,好怕怕)很见知识深度和修养,楼猪已经小有提防,但是这个问题还是再次让楼猪自乱阵脚。以前从来没人问过楼猪这个问题,楼猪也没主动想过它,脑袋里一片白茫茫,刚想要镇定下来,面试官又把相同问题问了一遍。不及细想,虽然不能确定,但是还是回答“应该可以...吧”(语气助词用得妙啊)。
肯定是对这个回答和回答的语气不满意,面试官又提醒问lock机制是什么样的,说说c#大概是怎么实现lock的。楼猪语无伦次说lock本质上和操作系统相关,lock就是当前线程将资源独占其他线程不能访问该锁定资源云云,背书都不会背了吗?无语了。面试官说回去自己试试吧。听他的语气,答案当然不言自明了,小心灵遭受重大挫折和打击啊。
回来后,验证了一下面试官的问题,程序运行到lock的时候,抛出ArgumentNullException异常,“值不能为null”。为什么lock一个指向null的引用实例不可以呢?
查了一下中文msdn:
lock 确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止),直到该对象被释放。
老实说,直到看到最后一句“对象被释放”才给了楼猪提示。某一对象可以指向null引用,但是null关键字是不需要释放的吧?!是吗?查了一下高人anytao的博客,发现这篇认识全面的null给出了明确的答案。
接着楼猪又查看了一下经常可以替代lock的Monitor类,赫然发现它的静态方法Enter(object obj)有一个异常类型ArgumentNullException,早知道,也不会那么狼狈啊。
2、lock的陷阱
除了msdn里提到的lock需要注意的两点外,园子里早就有高手总结过了,可以参考这一篇。
3、最后自己总结得出的三个结论:
a、c#中null是不能lock的(null会分配内存吗,会占用系统资源吗?和楼猪一起思考和探讨吧)。
b、高手一出手,往往可以化腐朽为神奇。
c、对自己说:
加油。