文章参考来源:http://www.cnblogs.com/zhili/p/SingletonPatterm.html
感谢:Learning hard
认知尚浅,如有错误,愿闻其详!
解析单例模式
单例模式作用在于保证让一个类只有一个实例对象。单例模式的实现过程就是一个控制它的方法。
1、例子
比如我们电脑中的任务管理器,同一时间内只允许一个实例对任务管理器中的进程进行操作。
(我们下面用创建单例窗口来展示)
这里为什么定义为静态的呢?对于这个疑问的解释为:每个线程都有自己的线程栈,定义为静态主要是为了在多线程确保类有一个实例
3、例子实现方式一(不推荐
):具体实现是将构造方法( Window1())私有化,提供一个访问它的全局静态访问点(GetInstance()方法)来创建实例对象,返回对象。
(在以该单例实现中,如果我们手动关闭了单例窗口,再次按下弹出窗口时,会报异常,源于该实例已经销毁,但是主窗口仍然尝试调用。所以关闭窗口后应将实例置为null)
public partial class Window1 : Window
{
private static Window1 singletonWin;//静态变量用来存储类的实例
/// <summary>
/// 私有化构造函数,以保证外部无法再次实例化对象
/// </summary>
private Window1()
{
InitializeComponent();
this.Closing += Window1_Closing;//关闭窗口事件
}
/// <summary>
/// 类中的全局访问点。
/// </summary>
/// <returns>返回实例对象</returns>
public static Window1 GetInstance()
{
if (singletonWin == null)//判断类是否已经实例化
{
singletonWin = new Window1();
}
return singletonWin;
}
/// <summary>
/// 在以上单例实现中,如果我们手动关闭了单例窗口,再次按下弹出窗口时,会报异常,源于该实例已经销毁,但是主窗口仍然尝试调用。所以关闭窗口后应将实例置为null
/// </summary>
private void Window1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
singletonWin = null;//置空
}
4、例子实现方式二(推荐
):为了解决方式一存在的线程安全问题,添加了一个标识(locker())和线程锁语句(lock{})来确保线程同步。解决过程如下:
假设,当前有多个线程调用该方法。
- 当第一个线程运行到此处时,线程会对locker对象进行加锁
- 第二个线程运行到此处时,首先会检测locker对象的状态(是否加锁),如果加锁,则会刮起,等待第一个线程执行完毕解锁
- lock语句执行完成后(即线程执行完毕)会进行该对象的解锁。
private static readonly object locker = new object();//定义一个标识确保线程同步
/// <summary>
/// 类中的全局访问点。加入线程锁
/// </summary>
/// <returns>返回实例对象</returns>
public static Window1 GetInstanceLock()
{
//////////////////////////////////////
///假设,当前有多个线程调用该方法。
///当第一个线程运行到此处时,线程会对locker对象进行加锁
///第二个线程运行到此处时,首先会检测locker对象的状态(是否加锁),如果加锁,则会刮起,等待第一个线程执行完毕解锁
///lock语句执行完成后(即线程执行完毕)会进行该对象的解锁。
/////////////////////////////////////
///为了避免锁所增加的额外性能开销,我们需要额外添加一个判断(if (singletonWin == null)),这个称为双重锁定。
if (singletonWin == null)//双重锁定只需要一句判断就可以了
{
lock (locker)//线程锁
{
if (singletonWin == null)//判断类是否已经实例化
{
singletonWin = new Window1();
}
}
}
return singletonWin;
}
(以上为单例窗口代码)
代码
主窗口代码
public MainWindow()
{
InitializeComponent();
btnSingleton.Click += BtnSingleton_Click;//注册点击事件
}
/// <summary>
/// 按钮点击事件
/// </summary>
private void BtnSingleton_Click(object sender, RoutedEventArgs e)
{
//Window1 win1 = Window1.GetInstance();//方式一创建窗口,存在线程安全问题
//win1.Show();
//win1.Focus();//获取焦点
Window1 win = Window1.GetInstanceLock();//方式二,添加线程锁,解决线程安全问题
win.Show();
win.Focus();
}
}