1经典模式
class Singleton
{
static Singleton instance;
Singleton() { }
public static Singleton Instance//静态属性?
{
get {
if (instance == null)
instance = new Singleton();
return instance;
}
}
}
该类构造函数被定义为private,静态属性Instance是客户程序获得类型实例的唯一入口。if语句控制实例创建的数量。该方式在多线程环境下存在缺陷。当多个线程几乎同时调用该类的Instance属性方法时,Instance成员可能还没被实例化,故它可能被不同线程创建了多次,各个线程引用了不同的实例。
2改进 double check方式
class Singleton
{
static volatile Singleton instance;
Singleton() { }
public static Singleton Instance
{
get {
if (instance == null)
lock (typeof(Singleton))
{
if(instance == null)
instance = new Singleton();
}
return instance;
}
}
}
说明:
1) 如果没有外层if,客户程序每次执行时都先lock住Singleton类型,但在绝大多数情况下,每次都锁定Singleton类型效率太差。
2) lock加内层if构成了一个相对安全的实例构造环境。
3) 一旦唯一的实例被创建后,后续新发起的调用无须经lock部分,直接在外层if判断后就可获得既有的唯一实例引用。
4) volatile关键字表示字段可能被多个线程修改。声明为volatile的字段不受编译器优化(一般默认的编译优化假定由单个线程访问)的限制,这样可以确保该字段在任何时间都呈现的是最新的值,即在被lock后,如果还没真正完成new Singleton(),新加入的线程看到的instance都是Null.
问题:构造过程为什么不放到静态构造函数中呢?
3多线程环境下实现单件模式的方式
class Singleton
{
Singleton() { }
public static readonly Singleton Instance = new Singleton();
}
说明
1) Instance是类的公共静态成员,故它会在类第一次被用到的时候构造出来。这样就不用把它的构造语句显示写在静态构造函数中。是因为对其进行了初始化了吗?
2) 此单件模式是线程安全的
4
public class Spooler {
static bool instance_flag = false; //true if one instance
public Spooler() {
if (instance_flag)
throw new SingletonException("Only one printer allowed");
else
instance_flag=true; //set flag for one instance
Console.WriteLine ("printer opened");
}
}
5需注意的地方
1) 不要实现ICloneable接口或继承自其相关的子类,否则客户程序可以跳过已经隐蔽起来的类构造函数。
2) 严防序列化。不能对期望具有Singleton特性的类型声明SerializableAttribute属性。