1.什么是单例模式
保证一个类最多只有一个实例(实例化控制),并且提供一个访问它的全局访问点(全局访问)。
2.什么时候用
当创建一个对象比较耗费资源,而这个对象的实例只要有一个就可以使用,这个时候可以用到单例模式。
单例模式解决了,如何实现一个类只能被创建一次的问题。
3.代码示例
using System;
namespace mydotnet
{
class Program
{
static void Main(string[] args)
{
Singleton singleton = Singleton.GetInstance();//客户端获取实例
}
}
public sealed class Singleton
{
private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用
private static Singleton instance;//必须是静态的,静态方法才能调用
public static Singleton GetInstance(){//公用静态方法,外部可以调用
if(instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
4.并发问题解决
上述代码是懒汉模式,第一次使用才会创建。发生并发时,可能会多次创建,解决并发可以考虑加lock。代码如下:
using System;
namespace mydotnet
{
class Program
{
static void Main(string[] args)
{
Singleton singleton = Singleton.GetInstance();//客户端获取实例
}
}
public sealed class Singleton
{
private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用
private static Singleton instance;//必须是静态的,静态方法才能调用
private static readonly object syncLock = new object();//不直接锁定 instance是因为instance不一定已经创建了,lock的内容需要非空的引用类型
public static Singleton GetInstance(){//公用静态方法,外部可以调用
lock(syncLock)
{
if(instance == null)
{
instance = new Singleton();
}
return instance;
}
}
}
}
lock的作用是锁定某一代码块,让同一时间只有一个线程访问该代码块,详细参考:https://www.cnblogs.com/liuqiyun/p/9118382.html
5.双重锁定
public static Singleton GetInstance(){//公用静态方法,外部可以调用
if(instance == null)//避免没必要的lock资源浪费
{
lock(instance)
{
if(instance == null)//不能去掉,如果同时进入lock还是可以重复创建
{
instance = new Singleton();
}
return instance;
}
}
}
6.饿汉模式
程序初始化时,就创建实例,不管用不用到。
饿汉模式,不要显式编写线程安全代码,就可以解决多线程环境下是否安全的问题。
解决方式使用静态初始化,代码如下:
using System;
namespace mydotnet
{
class Program
{
static void Main(string[] args)
{
Singleton singleton = Singleton.GetInstance();//客户端获取实例
}
}
public class Singleton
{
private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用
private readonly static Singleton instance = new Singleton();//静态初始化,不需要显式的线程安全代码 //readonly,只能在静态初始化期间或在类的构造函数中修改,不写也没事,防止在其他方法中修改
public static Singleton GetInstance(){
return instance;
}
}
}
也可以不写GetInstance方法,直接把instance设置为public,客户端直接写Singleton.instance实现更简单。
using System;
namespace mydotnet
{
class Program
{
static void Main(string[] args)
{
Singleton singleton = Singleton.instance;//客户端获取实例
}
}
public class Singleton
{
private Singleton(){}//私有化构造函数,防止外部实例化,内部可以使用
public readonly static Singleton instance = new Singleton();
}
}