|
四)第四种单件模式 public sealed class Singleton { private static Singleton _instance; private static object _lockHelper = new object(); private Singleton() { } public static Singleton Instance { get { if (_instance == null) { lock (_lockHelper) { if (_instance == null) { _instance = new Singleton(); } } } return _instance; } } public void DoSomething() { Console.WriteLine("做些事情"); } } 记得看到过有人这么问.为什么要双检查呢.为什么不改成如下代码? 1public static Singleton Instance 2{ 3 get 4 { 5 if(_instance == null) 6 { 7 lock(_lockHelper) 8 { 9 _instance = new Singleton(); 10 } 11 } 12 return _instance 13 } 14} 那我们来分析一下. 线程1执行到第8行停下来 线程2执行到第7行,因为线程1在lock里面,被阻塞,停下来 线程1继续执行第9行,初始化一个_instance设为obj1,退出lock区 线程2进入lock里面,也初始化一个_instance设为obj2,退出lock区 现在又是双件了.所以为什么要叫double-check双检查,也是来源与此. 这个单件模式被用的最多.但它就真的那么完美无缺吗? 不 因为上面的代码被编译,编译器由于考虑时间和空间的问题,会对代码进行优化,指令的顺序可能也会被改变. 所以在多线程中可能还是会出状况,虽然这种概率很低,但要是有解决方法为什么不用呢? 那就来看第五种单件模式 五)第五种单件模式 public sealed class Singleton { private static volatile Singleton _instance; private static object _lockHelper = new object(); private Singleton() { } public static Singleton Instance { get { if (_instance == null) { lock (_lockHelper) { if (_instance == null) { _instance = new Singleton(); } } } return _instance; } } public void DoSomething() { Console.WriteLine("做些事情"); } } 小菜并没有做多少事,只是把private static Singleton _instance;修改为private static volatile Singleton _instance; volatile关键字有这么大魔力? 对 编译器保证对此_instance的读写操作都不会被优化. 接下来我们来讲个集万千宠爱与一生的单件模式 六)第六个单件模式 public sealed class Singleton { private Singleton() { } public static Singleton Instance { get { return Nested.instance; } } public void DoSomething() { Console.WriteLine("做些事情"); } //嵌套类 private class Nested { internal static readonly Singleton instance; private Nested() { } static Nested() { instance = new Singleton(); } } } return Nested.instance保证了原子性. 第一次执行它时 1.为Netsted的静态数据成员Singleton instance分配内存空间,存储空间的值为null 2.执行instance的静态初始语句,由于没有所以跳过 3.执行静态构造函数,执行 instance = new Singleton() 初始化instance 4.返回instance对象 很明显用到的知识还是前面的对象构造顺序,可见有多重要. 到这里单件模式的多种实现都介绍完了. |