对于单例模式先来一个C#版本的初级不能用的版本:
版本一不可行方法:
public class Singleton { private Singleton() {} private static Singleton instance = null; public static Singleton getInstance() { if(instance == null) instance = new Singleton(); return instance; } }
之所以说这是一个不能用的初级版本,因为它仅仅能用在单线程的情况下。在多线程并发的情况下是不能保持单例的。
这里的不安全的地方是,多个线程同时对instance判断都为null,然后都new一个实例,所以要在判instance为null的那段代码加互斥锁。
版本二可行低效方法:
public class Singleton { private Singleton() {} private static Singleton instance = null; private static readonly object syncobj = new object(); public static Singleton getInstance() { lock(syncobj) { if(instance == null) instance = new Singleton(); } return instance; } }
但是这种互斥锁是很消耗操作的,在没有必要的时候,尽量少做互斥锁。
所以做一个轻微的调整:
public class Singleton { private Singleton() {} private static Singleton instance = null; private static readonly object syncobj = new object(); public static Singleton getInstance() { if(instance == null) { lock(syncobj) { instance = new Singleton(); } } return instance; } }
忽然发现这同样是不能多线程的,所以要在加一层对instance的判断null。
版本三可行方法:
public class Singleton { private Singleton() {} private static Singleton instance = null; private static readonly object syncobj = new object(); public static Singleton getInstance() { if(instance == null) { lock(syncobj) { if(instace == null) { instance = new Singleton(); } } } return instance; } }
这样就能够支持多线程了,是一种可行的方法。
版本四推荐的版本:
public class Singleton { private Singleton() {} private static Singleton instance = null; //静态构造函数,对静态成员变量初始化 static Singleton() { instance = new Singleton(); } public static Singleton getInstance() { return instance; } }
下面对静态构造函数做一个科普:
静态构造函数用来初始化静态变量,这个构造函数是属于类的,而不是属于哪个实例的。
就是说这个构造函数只会被执行一次。也就是在创建第一个实例或引用任何静态成员之前,由.NET自动调用。
静态构造函数的特点:
1.静态构造函数既没有访问修饰符,也没有参数。
2.在创建第一个实例或引用任何静态成员之前,将自动调用静态构造函数来初始化类,也就是无法直接调用静态构造函数,也无法控制什么时候执行静态构造函数。
3.一个类只能有一个静态构造函数,最多只能运行一次。
4.静态构造函数不可以被继承。
5.如果没有静态构造函数,而类中的静态成员有初始值,那么编译器会自动生成默认的静态构造函数。
从这里可以看出静态构造函数的调用时机不是由程序员掌控的,而是当.NET运行时发现第一次使用一个类型的时候自动调用该类型的静态构造函数。
但是这种方法会过早的穿件实例,从而降低了内存的使用效率。
版本五更高级的版本:
现在想做的就是不要一碰到Singleton就申请一个静态实例,要等到我调用getInstance的时候才申请实例空间。所以做一个内部类
public class Singleton { private Singleton(){} public static Singleton getInstance() { return Nested.instance; } //外部类只可以访问内部类的public和interal权限的字段、方法、属性 //嵌套类可以访问外部类的方法、属性、字段而不受访问修饰符的限制 class Nested { static Nested() { instance = new Singleton(); } internal static Singleton instance = null; } }