最近在asp.net项目中碰到的一个问题。
一个编码器模块使用单实例实现,结果碰到了编码ID重复的异常。
public class IdGenerator
{
private static IdGenerator single;
public static IdGenerator Single
{
get
{
if (null == single)
{
single = new IdGenerator();
}
return single;
}
}
protected IdGenerator()
{
init();
}
......
}
仔细看了代码,只可能是多线程环境下,创建实例的问题。两个线程同时运行到这一句:
if (null == single)
就可能创建两个实例。虽然几率很小,不过init()操作中会有一些读数据库的耗时操作,asp.net服务启动之后,某个网页同时被两个人访问,可能就会触发这个异常。
上网查到微软官方的一篇文档,肯定了我的推断:Implementing Singleton in C#
合理的单实例实现应该是:
public sealed class Singleton
{
// volatile 声明确保 instance 变量赋值完成后才被访问
private static volatile Singleton instance;
private static object syncRoot = new Object();
private Singleton() {}
public static Singleton Instance
{
get
{
if (instance == null)
{
// 通过加锁来避免多线程下的问题
lock (syncRoot)
{
if (instance == null)
instance = new Singleton();
}
}
return instance;
}
}
}