保证一个类仅有一个实例,并提供一个访问它的全局访问点。
1、基本单例模式
让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。最好的办法是让类自身负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方法。
public class Singleton
{
private static Singleton instance;
//构造方法为private,这样就堵死了外界用new创建此实例的可能
private Singleton()
{
}
//此方法是获得本实例的唯一全局访问点
public static Singleton GetInstance()
{
//若实例不存在,则创建一个新的,否则返回以存在的实例
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
{
private static Singleton instance;
//构造方法为private,这样就堵死了外界用new创建此实例的可能
private Singleton()
{
}
//此方法是获得本实例的唯一全局访问点
public static Singleton GetInstance()
{
//若实例不存在,则创建一个新的,否则返回以存在的实例
if (instance == null)
{
instance = new Singleton();
}
return instance;
}
}
static void Main(string[] args)
{
// Singleton s = new Singleton();报错,因为构造方法被变成private,防止外界创建实例
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.WriteLine("Same");
}
Console.Read();
//运行结果为Same表示s1和s2是同一个实例,即Singleton只生能生成一个实例
}
{
// Singleton s = new Singleton();报错,因为构造方法被变成private,防止外界创建实例
Singleton s1 = Singleton.GetInstance();
Singleton s2 = Singleton.GetInstance();
if (s1 == s2)
{
Console.WriteLine("Same");
}
Console.Read();
//运行结果为Same表示s1和s2是同一个实例,即Singleton只生能生成一个实例
}
2、多线程时的单例
多线程时多个线程同时访问Singleton类,调用GetInstance()方法,会有可能造成创建多个实例。此时需要对进程进行锁定。
public class Singleton
{
private static Singleton instance;
//程序运行时创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
private Singleton()
{
}
public static Singleton GetInstance()
{
//在同一时刻加锁的那部分程序只有一个线程可以进入
//lock是确保当一个线程位于代码临界区时,如果另一线程企图进入锁定的代码,则它将一直等待
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
return instance;
}
}
{
private static Singleton instance;
//程序运行时创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
private Singleton()
{
}
public static Singleton GetInstance()
{
//在同一时刻加锁的那部分程序只有一个线程可以进入
//lock是确保当一个线程位于代码临界区时,如果另一线程企图进入锁定的代码,则它将一直等待
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
return instance;
}
}
此时,问题虽然解决,但每次调用GetInstance时都要lock会影响性能,于是就有了双重锁定。
public class Singleton
{
private static Singleton instance;
private static readonly object syncRoot = new object();
private Singleton()
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
lock (syncRoot)
{
//第二次还要判断是因为如果有两个进程同时访问则都能通过第一个,如果没有第二次的判断则会产生两个实例。
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
{
private static Singleton instance;
private static readonly object syncRoot = new object();
private Singleton()
{
}
public static Singleton GetInstance()
{
if (instance == null)
{
lock (syncRoot)
{
//第二次还要判断是因为如果有两个进程同时访问则都能通过第一个,如果没有第二次的判断则会产生两个实例。
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
3、静态初始化
//sealed阻止发生派生,而派生可能会增加实例
public sealed class Singleton
{
//在第一次引用类的任何成员时创建实例。
private static readonly Singleton instance=new Singleton();
private Singleton()
{
}
public static Singleton GetInstance()
{
return instance;
}
}
public sealed class Singleton
{
//在第一次引用类的任何成员时创建实例。
private static readonly Singleton instance=new Singleton();
private Singleton()
{
}
public static Singleton GetInstance()
{
return instance;
}
}
在类声明中使用sealed可防止其它类继承此类;在方法声明中使用sealed修饰符可防止扩充类重写此方法。
静态初始化方式在自己被加载时就将自己实例化,被称为饿汉式单例,它要提前占用资源;前面的在第一次引用时将自己实例化,被称为懒汉式单例,它要考虑多线程访问的安全性。
4、常用功能
资源管理