单例模式(Singleton):保证一个类仅有一个实例,并提供一个访问它的全局访问点。
-
单例模式根据实例化的时间不同分为懒汉式和饿汉式两种。
- 静态初始化的方式表示应用单例模式的类在自己被加载时就将自己十六啊,成为饿汉式单例类。(饿汉已经很饿,尽一切可能,第一时间实例化,也就是程序还没运行,只加载就把自己给实例化了。)
- 而应用单例模式的类在第一次被引用时,才将自己实例化,这叫做懒汉式单例类。(懒汉很懒,程序都运行起来了,他也不管,当有类跟他说,嗨,兄弟,我要访问你的方法。”这时,才懒洋洋地把自己实例化,供对方调用。)
-
多线程环境下的不安全问题
- 当应用饿汉式的时候,我们作为开发人员,不必考虑,这个事儿由公共语言运行库负责。公共语言运行库是什么,目前我也不知道。现在不做探究,只要知道有人(程序)负责就好了。
- 当应用懒汉式的时候,是需要考虑这个问题的。解决办法就是双重锁定。双重锁是怎样的,别着急,边看代码边说道。
在合作中,我用的是懒汉式。
主窗体就是MDI父窗体,应用了单例模式。作为例子,来看看代码。
//应用单例模式的类
public partial class FrmMain : Form
{
private int childFormNumber = 0;
#region 单例模式-饿汉式-李爽-2016年1月18日15:30:12
//单例模式--饿汉式
private static FrmMain instance;
//创建一个静态只读的进程辅助对象
private static readonly Object SyncRoot = new Object();
//构造方法私有
private FrmMain()
{
InitializeComponent();
}
public static FrmMain GetInstance()
{
//双重锁定
if (instance == null || instance.IsDisposed)//先判断实例是否存在,不存在,再加锁处理
{
lock (SyncRoot)//加锁,只允许一个线程进入
{
if (instance == null || instance.IsDisposed)//若实例不在,new一个新实例
{
instance = new FrmMain();
}
}
}
return instance;//否则返回已有的实例:
}
#endregion
双重锁是为了改良程序,只在实例未被创建的时候再加锁处理。
相对的,单个锁的情况,也就是没有外层IF判断的情况,是每次要引用这个类,无论它已经被实例化了还是未被实例化,都要加锁。显而易见,总加锁,是多么影响效率的一件事情。一到这儿就卡顿一下,卡顿,卡顿,卡顿,,,,卡卡卡,,,所以,双重锁,完美。
但是调用代码,也就是单例模式的客户端代码,普通窗体和MDI子窗体,在代码上还是有些区别的,这个区别,跟单例模式无关,跟MDI父子窗体有关。
在登录窗体里调用主窗体,代码为:
//单例模式客户端
FrmMain frmMain = FrmMain.GetInstance();
frmMain.Show();
在主窗体里调用子窗体,代码为:
#region 打开学生余额查询窗体
/// <summary>
/// 打开学生余额查询窗体
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ShowNewForm(object sender, EventArgs e)
{
//单例模式客户端
FrmQueryBalance frmQueryBalance = FrmQueryBalance.GetInstance();
frmQueryBalance.TopLevel = false;
this.panel1.Controls.Add(frmQueryBalance);
frmQueryBalance.BringToFront();
frmQueryBalance.Show();
}
#endregion
【总结】
至此,单例模式OK了。