单例介绍
- 静态方法只能访问静态数据成员
- 单例模式保证类只有一个对象
- 该唯一对象由类内部创建
- 类向外部提供访问该唯一对象的接口,将构造函数说明为私有,可以避免外部创建对象.
饿汉单例
饿汉单例在类被加载时就以及将唯一的对象实例化出来了,没有达到Lazy load,内存开销比较大.饿汉单例优点是不存在线程安全的问题.
懒汉单例
在外部第一次向类调用接口访问唯一对象时再去创建对象,达到了Lazy load,但是会有线程安全的问题.
线程安全的懒汉单例写法
public sealed class A
{
private A()
{}
private static readonly object sysncobj=new object();
private static A instance=null;
public static A Instance
{
if(syscobj)
{
if(instance ==null)
{
instance= new A();
}
return instance;
}
}
}
当两个线程同时调用Instance属性时,不加锁的写法,如果instance为空,两个线程都会创建一个实例.
加同步锁,当一个线程在执行临界区代码时,其他线程不能执行.当一个线程执行完同步锁里面的代码时,另一个线程进入临界区代码,此时instance不为空,不会再创建另外的实例,保证了单例在多线程环境下创建出唯一实例.
上述单例的优化
以上单例写法在每次通过Instance属性得到实例的时候都会试图加上一个同步锁,而加锁是一个比较耗费性能的操作。
public static A Instance
{
if(instance==null)
{
if(syscobj)
{
if(instance ==null)
{
instance= new A();
}
return instance;
}
}
}
只有判断没有实例的时候,才会加锁再进行其他的操作.
例如,两个线程在一开始同时需要得到唯一实例,此时instance都为空,一个线程会执行临界区代码,将唯一实例创建出来.另一个线程访问临界区时,第二次判断的instance已经不为空了,直接返回,不会再创建实例,保证了单例的唯一性.
以上代码只有在单例对象没有创建出来的时候才会执行加锁操作,此后每次调用都不会加锁,效率更好.