单例模式顾名思义,就是一个类只有一个实例,应用广泛,写法较多,下来做一下简单的总结说明:
(一)单线程写法,主要根据项目开发类型选择,如果是单线程项目,推荐指数–》“+++++”
C#写法:
public class Singleton1
{
private Singleton1(){}
private static Singleton1 m_instance = null;
public static Singleton1 Instance{
get{
if (m_instance == null)
{
m_instance = new Singleton1();
}
return m_instance;
}
}
}
思考:如果我们只有一个线程跑,那么没什么问题,但是如果是多线程,这个时候,如果有三个线程同时跑到了这里,判断m_instance是否被创建怎么办,他们都会发现这个对象为空,然后分别为它创建一个实例,这样就不满足单例模式了,我们的类就会被创建多个对象,所以需要优化。
(二)多线程写法(加同步锁),推荐指数–》“+”
c#写法:
public class Singleton2
{
private Singleton2(){}
private static readonly object syncLockObj= new object();
private static Singleton2 m_instance = null;
public static Singleton2 Instance{
get{
lock(syncLockObj)
{
if (m_instance == null)
{
m_instance = new Singleton2();
}
}
return m_instance;
}
}
}
思考:如果我们有好几的线程都跑到了这里,但是在同一个时刻只有一个线程可以获得一个同步锁,那么当第一个获得同步锁的线程给它上锁以后,别的线程就只能等待了,那么如果他发现还没有创建实例,我们再去创建实例对象,然后释放同步锁,返回对象,这样就可以让我们的类在多线程的模式下也可以始终保持一个对象。但是我们发现,每次再获取它的时候都会先上锁再去判断,可是上锁是一个非常耗时的操作,在没有必要的时候我们应该尽量避免,于是我们还需要优化这里。
(三)加同步锁优化后写法,推荐指数–》“+++”
c#写法:
public class Singleton3
{
private Singleton3() { }
private static readonly object syncLockObj = new object();
private static Singleton3 m_instance = null;
public static Singleton3 Instance
{
get
{
if (m_instance == null)
{
lock (syncLockObj)
{
if (m_instance == null)
{
m_instance = new Singleton3();
}
}
}
return m_instance;
}
}
}
思考:我们发现,其实我们只需要在它为空的时候上锁,然后去创建对象,因为单例只有一个对象,所以它为空的时候才回去执行,大大减少了我们上锁的次数,减少消耗,这样好像就可以了。但是,程序员其实很懒的,我们的功能是实现了,可以使用了,但是写起来看上去有些复杂,我们可不可以优化一下写法。
(四)静态构造函数写法,推荐指数–》“++++”
c#写法:
public class Singleton4
{
private Singleton4() { }
private static Singleton4 m_instance = new Singleton4();
public static Singleton4 Instance
{
get
{
return m_instance;
}
}
}
思考:我们的代码好像少了很多,我们在初始化变量的时候就给它赋值了对象,这样我们在多线程中也不用加锁了,谁要直接给,看上去好像没什么问题,但是我们仔细分析一下:C#调用静态构造函数的实际不是由程序员自己控制的,而是当.NET运行时发现第一次使用一个类型的时候自动调用该类型的静态构造函数的。所以实例m_instance实例对象不是在第一次调用Singleton4.Instance的时候被创建的,而是第一次用到Singleton4的时候就被创建了,如果这样实现的话,就会导致这个对象被我们过早的创建出来占用内存了,实际上我们更希望的是按需创建,这样可以优化我们内存,不至于造成内存浪费。,于是我们就有了下一个方法。
(五)按需创建写法,推荐指数–》“+++++”
c#写法:
public class Singleton5
{
private Singleton5() { }
private class SingleCreate
{
static SingleCreate() { }
internal static readonly Singleton5 m_instance = new Singleton5();
}
public static Singleton5 Instance
{
get
{
return SingleCreate.m_instance;
}
}
}
思考:我们在单例类的内部创建了一个私有类,用它来创建我们的单例对象,只有当我们的单例Singleton5.Instance第一次调用的时候,我们才会去创建我们的单例对象,真正做到了按需创建对象,优化了内存。