- A+
所属分类:.NET技术
class STWindow { static Window win; private STWindow() { } public static Window GetInstance() { if (win == null || !win.IsVisible) { win = new Window(); win.Height = 200; win.Width = 200; } return win; } } class Singleton { static Singleton _singleton; private Singleton() { } public static Singleton GetInstance() { if (_singleton == null) { _singleton = new Singleton(); } return _singleton; } }
1. 多线程同时创建实例问题
多个线程同时访问 Singleton 的 GetInstance() 方法,可能会造成创建多个实例;
比如 A 先进入后在准备实例化 Singleton 的过程中,B 也进入了,这时 _singleton 还是为 null,然后 B 也去实例化 Singleton 了。
class Singleton { static Singleton _singleton; private Singleton() { } public static Singleton GetInstance() { if (_singleton == null) { Console.WriteLine("实例化一个 Singleton"); _singleton = new Singleton(); } Console.WriteLine("返回一个 Singleton"); return _singleton; } } System.Threading.Thread a = new System.Threading.Thread(() => { Singleton.GetInstance(); }); System.Threading.Thread b = new System.Threading.Thread(() => { Singleton.GetInstance(); }); System.Threading.Thread c = new System.Threading.Thread(() => { Singleton.GetInstance(); }); a.Start(); b.Start(); c.Start();
实例化一个 Singleton 实例化一个 Singleton 返回一个 Singleton 返回一个 Singleton 返回一个 Singleton
我们通过加个锁来解决这个问题。
public static readonly object syncRoot = new object(); public static Singleton GetInstance() { lock (syncRoot) { if (_singleton == null) { Console.WriteLine("实例化一个 Singleton"); _singleton = new Singleton(); } } Console.WriteLine("返回一个 Singleton"); return _singleton; }
实例化一个 Singleton 返回一个 Singleton 返回一个 Singleton 线程 0x1a08 已退出,返回值为 0 (0x0)。 返回一个 Singleton 线程 0x45b4 已退出,返回值为 0 (0x0)。 线程 0x5a04 已退出,返回值为 0 (0x0)。
2. 每次实例都要锁的性能问题
使用双重锁定,只有未实例化时才锁,锁完判断是否还未实例化。
public static Singleton GetInstance() { if (_singleton == null) { lock (syncRoot) { if (_singleton == null) { _singleton = new Singleton(); } } } return _singleton; }
3.饿汉式单例
class Singleton { static readonly Singleton _instance = new Singleton(); private Singleton() { } public static Singleton GetInstance() { return _instance; } }
这种静态初始化的方式是自己被加载时就将自己实例化,因此被称为饿汉式单例;
而第一次被引用时才将自己实例化的方式被称为懒汉式单例。C# 中饿汉式已足够满足。