题目:设计一个类,我们只能生成该类的一个实例。
解法一:只适用于单线程
代码如下:
public sealed class SingleTon1 { public static void Print() { Console.WriteLine("Singleton1 print"); } private SingleTon1() { Console.WriteLine("An instance of Singleton1 is created."); } private static SingleTon1 instance = null; public static SingleTon1 Instance { get { if (instance == null) instance = new SingleTon1(); return instance; } } }
输出:Singleton1 print
分析:Print方法用于主函数调用,后面的亦是。声明一个private的构造函数是为了无法在类的外部创建实例,确保只创建一个实例。后面的就是常规写法了。那么,为什么无法用于多线程呢?设想一下,当多个线程同时执行到Instance的if语句时,这时候会创建多个实例,这就不是单例模式了,单例模式是只有一个实例的。
解法二:使用同步锁,使得可在多线程环境中使用
代码如下:
public sealed class Singleton2 { private Singleton2() { Console.WriteLine("An instance of Singleton2 is created."); } public static void Print() { Console.WriteLine("Singleton2 print"); } private static readonly object syncObj = new object(); private Singleton2 instance = null; public Singleton2 Instance { get { lock(syncObj) { if(instance==null) { instance = new Singleton2(); } } return instance; } } }
输出:Singleton2 print
分析:这个为什么多线程也适用呢?因为我们先创建了一个object实例,使用lock时只有一个syncObject可以进入判断,也就是只有一个线程可以进入判断,当后面的线程进入时已经有了实例,就不会再创建了,这就符合单例模式一个实例的原则。这个解法有什么缺点呢?每次调用Instance属性创建实例时都有加锁的动作,之后又要释放同步锁,很消耗时间。
解法三:使用同步锁前先进行判断
代码如下:
public sealed class Singleton3 { private Singleton3() { Console.WriteLine("An instance of Singleton3 is created."); } public static void Print() { Console.WriteLine("Singleton3 print"); } private static readonly object syncObj = new object(); private static Singleton3 instance = null; public static Singleton3 Instance { get { if(instance==null) { lock(syncObj) { if (instance == null) instance = new Singleton3(); } } return instance; } } }
输出:Singleton3 print
分析:在加锁之前先判断实例是否存在,若已有实例,则不会再加同步锁。为什么加锁之后还要判断实例是否存在呢?同样可以设想多个线程同时到第一个if语句那里的情况。不过这样的代码实现起来比较复杂,容易出错。
解法四:使用静态构造函数
代码如下:
public sealed class Singleton4 { private Singleton4() { Console.WriteLine("An instance of Singleton4 is created."); } public static void Print() { Console.WriteLine("Singleton4 print"); } private static Singleton4 instance = new Singleton4(); public static Singleton4 Instance { get { return instance; } } }
输出:An instance of Singleton4 is created.
Singleton4 print
分析:静态函数在哪里呢?当有静态成员初始化的时候,编译器会生成一个默认静态构造函数,也就是instance初始化的时候。然后,静态构造函数是只会调用一次的,所以只会有一个实例。不过,这种解法还有一点不完美,就是无论用不用Instance属性,它都会生成一个实例,那么,能不能改进呢?是可以的。为什么会输出An instance of Singleton4 is created.呢?因为在实例化的时候会调用我们声明的那个私有构造函数,因为是在类的内部实例化。
解法五:嵌套类的静态构造函数
代码如下:
public sealed class Singleton5 { private Singleton5() { Console.WriteLine("An instance of Singleton5 is created."); } public static void Print() { Console.WriteLine("Singleton5 print"); } public static Singleton5 Instance { get { return Nested.instance; } } class Nested { static Nested() { } internal static readonly Singleton5 instance = new Singleton5(); } }
输出:Singleton5 print
分析:当使用Instance属性的时候才会创建实例。
Main方法:
class Program { static void Main(string[] args) { SingleTon1.Print(); Singleton2.Print(); Singleton3.Print(); Singleton4.Print(); //一创建实例就会调用构造函数 Singleton5.Print(); Console.ReadKey(); } }