使用环境
某个对象只需要一个实例的情况,比方说GameManager,ResourceManager
简单例子
using System;
namespace 单例模式
{
class Singleton
{
// 定义一个静态变量来保存类的实例
private static Singleton instance;
// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{ }
//定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
public static Singleton GetInstance()
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
口诀要领
构造私有,全局访问入口
多线程例子
上面那个例子不是线程安全的,多线程这么写:
using System;
namespace 单例模式
{
class Singleton
{
// 定义一个静态变量来保存类的实例
private static Singleton instance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{ }
//定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
public static Singleton GetInstance()
{
lock(locker)
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
}
这个例子中确实可以解决多线程的问题,但是上面代码对于每个线程都会对线程辅助对象locker加锁之后再判断实例是否存在,对于这个操作完全没有必要的,因为当第一个线程创建了该类的实例之后,后面的线程此时只需要直接判断(instance==null)为假,此时完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销,损失了性能,为了改进上面实现方式的缺陷,我们只需要在lock语句前面加一句(instance==null)的判断就可以避免锁所增加的额外开销,这种实现方式我们就叫它 “双重锁定”。修改如下:
using System;
namespace 单例模式
{
class Singleton
{
// 定义一个静态变量来保存类的实例
private static Singleton instance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private Singleton()
{ }
//定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
public static Singleton GetInstance()
{
if(instance==null)
{
lock(locker)
{
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
}
}
单例模式比较常用,自己根据实际项目中进行体会,当然单例是静态的,必要的时候注意释放资源哦。。。不明白的地方欢迎交流。。。