前情回顾:
不知大家是否曾有过类似经历。在做机房收费的时候,单击菜单栏的某个按钮,click 一次便出现一次此窗体,从而导致一个主界面里出现过多相同的窗体,但理想状态是不管如何单击,一个主界面我们只想要某窗体只出现一次。此时,单例模式便可派上大用场。
计划生育,还是一个好:
懒汉单例模式:
单例模式是相对于众多模式中最严谨守法的好模式。它能保证一个类只有唯一一个对象被实例化,并只提供一个全局访问点。
具体方法是在需要单例的类中写入私有的构造方法,导致外界不能使用new创建实例。再定义一个访问本类实例的唯一一个全局访问点,从中判断此类有否被实例化过,如果没有,实例化此类。如果已经实例化,则显示已实例化对象。
具体代码如下:
Class Singleton
{
Private static Singleton instance;
Private Singleton() //将instance构造方法设定为私有,防止对其无限实例化。
{
}
Public static Singleton GetInstance()//写出一个全局公有的GetInstance方法,来对instance进行判断,最后访问。
{
If (instance==null)
{
Instance=new Singleton();
}
Return instance;
}
}
结构图如下:
多线程时的单例:
1、锁定
在操作系统概论一书中,详细讲述了线程等概念,在此不再赘述。
多线程时,同时访问此类调用GetInstance方法,也有可能导致创建出多个实例。可以利用lock锁,让个线程有条不紊的one by one依次进入。
Class Singleton
{
Private static Singleton instance;
Private static readonly object syncRoot=new object()//创建一个进程辅助对象。
Private Singleton()
{
}
Public static Singleton GetInstance()//
{
Lock (syncRoot) //加锁部分,只有一个线程可进入,别的排队等待。
{
If (instance==null)
{
Instance=new Singleton();
}
}
Return instance;
}
}
2、双重锁定
但是这样我们就让线程每次都给加锁,不断的重复。所以可以优化一下,先进行判断,只对没有实例化的时候再加锁处理,防止多个getinstance被调用。这就是传说中的双重锁定。
Double-check lock:
Class Singleton
{
Private static Singleton instance;
Private static readonly object syncRoot=new object()//创建一个进程辅助对象。
Private Singleton()
{
}
Public static Singleton GetInstance()//
{
If (instance==null) //先判断,不存在被实例化的instance时,才进行加锁处理。
{
Lock (syncRoot)
{
If (instance==null)
{
Instance=new Singleton();
}
}
}
Return instance;
}
}
懒汉静态初始化:
其实严于律己遵守国家规章制度的不只单例一人,还有一位“静态初始化”君。通过一个秘密的sealed关键字达到同样防止多生的效果。
具体实现如下:
Public sealed class Singleton
{
Private static readonly Singleton instance=new Singleton();
Pirvate Singleton()
{
}
Public static Singleton GetInstance()\
{
Return instance;
}
}
饿汉 vs 懒汉
至于饿汉懒汉的称谓主要来源于单例模式要在此一次被引用时,才将自己实例化,相对于静态初始化在自己一被加载的时候就积极实例化而言,表现得懒惰不积极,所以单例模式是个大懒蛋。而静态初始化方法又显得稍微有点太积极主动了,太希望实现自我价值了,早早的就给自己占了个空间。所以被称为饿汉式单例类。不过懒汉饿汉,只要遵纪守法,就是好汉。