一个多线程下的单实例实现故障
最近在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; } } }