题目:设计一个类,我们只能生成该类的一个实例。
解法一:只适用于单线程
代码如下:
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();
}
}