学习了单例模式,自己记一下笔记,本文从一个单例模式开始进行一步一步的演进,使用c#语言,在实现上会结合C#的特性。演进过程为 单线程无参数单例模式->多线程无参数单例模式->.net特性多线程无参数单例模式->单线程有参数单例模式->多线程有参数单例模式->.net特性多线程有参数单例模式
public class Singleton
{
private static Singleton instance;
private Singleton() { }
public static Singleton Instance
{
get
{
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
我们以一个最简单的单例模式起手,单例模式顾名思义就是要让该类只有一个初始化的对象,首先我们需要做的是将对象的构造方法进行私有化,这样改对象就不能在外部进行实例化new,从下图可以看到当我们进行private私有化之后,在外部已经不能访问了。
下面我们在该函数内部进行实例化,进行判空如果对象没有被实例化就进行示例化,该单例模式只试用与单线程使用。为什么只能在单线程中使用?我们可以看到在每次调用Instance的时候都会进行执行if (instance == null)
进行判空,但是当在多线程的时候,有可能两个线程同时满足该条件,例如:在第一个线程判断为空后,还没有进行实例化,这时候第二个线程进行了判空,将进入该语句,这样的情况就会进行两次实例化。下面我们修改这个方法让多线程可以安全使用
public 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;
}
}
}
这是一个可以多线程使用的单例模式,进行了加锁,并进行了两次判断。private static object lockHelper = new object(); 这里可以任意写一个对象,只是用于加锁使用。
class Singleton
{
public static readonly Singleton Instance = new Singleton();
private Singleton() { }
}
这段代码可以说是非常精简,可以扩展下看着更清晰
class Singleton
{
public static readonly Singleton Instance;
static Singleton()
{
Instance = new Singleton();
}
private Singleton() { }
}
在第一种方式中我们使用了内联初始化,在.net中会将初始化内容放入构造器中初始化,因为是静态变量所以为静态初始化器所以如下面的代码。 静态初始化器执行时期:在静态字段初始化之前进行初始化,如Singleton类就是当调用Instance时会进行初始化 我们用下面的代码测试一下执行时机:
static void Main(string[] args)
{
Console.WriteLine("---------");
Singleton t1 = null;
Console.WriteLine("---------");
Singleton t2 = Singleton.Instance;
Console.WriteLine("---------");
Singleton t3 = Singleton.Instance;
Console.ReadKey();
}
class Singleton
{
public static readonly Singleton Instance;
static Singleton()
{
Console.WriteLine("静态构造器初始化");
Instance = new Singleton();
}
private Singleton() { }
}
执行结果:
我们可以看到在第一次调用Instance时才会发生初始化,这样就是一个基于.net特性的单例模式。
有参数的单例模式我这里就不再详细讲解,给大家贴上代码供参考 单线程:
//单线程
public class Singleton
{
int x;
int y;
private static Singleton instance;
private Singleton(int x,int y)
{
this.x = x;
this.y = y;
}
public static Singleton GetInstance(int x, int y)
{
if (instance == null)
{
instance = new Singleton(x, y);
}
else
{
instance.x = x;
instance.y = y;
}
return instance;
}
}
多线程:
//多线程
public class Singleton
{
int x;
int y;
private static volatile Singleton instance;
private static object lockHelper = new object();
private Singleton(int x,int y) {
this.x = x;
this.y = y;
}
public static Singleton GetInstance(int x,int y)
{
if (instance == null)
{
lock (lockHelper)
{
if (instance == null)
{
instance = new Singleton(x,y);
}
else
{
instance.x = x;
instance.y = y;
}
}
}
return instance;
}
}
.ne特性的代码,大家直接声明字段然后赋值就可以了,这里就不示范了。