单例的用处
单例就是对象常驻内存,重用对象。
单例的用途场景:
- 数据库连接池
- 线程池
- 流水号生成器
- 配置文件读取
- IOC容器实例
但是同一个实例,不能解决多线程并发引起的线程安全问题。
单例模式–简单版
单例模式:保证进程中,类型只有一个实例
- a) 构造函数私有化,防止他人实例化
- b) 对外提供一个获取实例的途径,公开的静态方法
- c) 返回共用一个静态字段
此种方式不支持多线程。
public sealed class Singleton
{
private Singleton()
{
}
private static Singleton _Singleton = null;
public static Singleton CreateInstance()
{
if (_Singleton == null)
{
_Singleton = new Singleton();
}
return _Singleton;
}
}
单例模式–双判断+锁
该种方式的单例模式支持多线程。
通过lock加锁可以保证任意时刻只有一个线程进入,其他线程等待;
正常的流程为:开始多线程初始化—>lock锁定—>线程请求锁—>开始判断对象是否需要创建,但是这样的多个线程请求都需要等待锁,所以最好在等待锁外层加一个先判断对象是否为空。这样就形成了双判断+锁的单例模式。
public sealed class Singleton
{
private Singleton()
{
}
private static Singleton _Singleton = null;
private static readonly object Singleton_Lock = new object();
public static Singleton CreateInstance()
{
if (_Singleton == null)
{
lock (Singleton_Lock)//可以保证任意时刻只有一个线程进入,其他线程等待
{
if (_Singleton == null)//这个判断不能去掉,保证只初始化一次
{
_Singleton = new Singleton();
}
}
}
return _Singleton;
}
}
单例模式–静态构造函数
静态构造函数:由CLR保证,在第一次使用到这个类型之前,自动被调用且只调用一次。
该种方式的单例模式支持多线程。
public sealed class Singleton
{
private Singleton()
{
}
private static Singleton _Singleton = null;
/// <summary>
/// 静态构造函数:由CLR保证,在第一次使用到这个类型之前,自动被调用且只调用一次
/// 很多初始化都可以写在这里
/// </summary>
static SingletonSecond()
{
_SingletonSecond = new SingletonSecond();
}
public static SingletonSecond CreateInstance()
{
return _SingletonSecond;
}
}
单例模式–静态字段
静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且只初始化一次。
该种方式的单例模式支持多线程。
public sealed class Singleton
{
private Singleton()
{
}
/// <summary>
/// 静态字段:由CLR保障,在第一次使用这个类型之前,会自动初始化且只初始化一次
/// </summary>
private static SingletonThird _SingletonThird = new SingletonThird();
public static SingletonThird CreateInstance()
{
return _SingletonThird;
}
}