浅谈单例模式

单例模式
需求:
写一个MDI 窗体程序,当有一个是“工具箱”的窗体,想要实现点击(可以多次点击)工具箱出现一次,不是出现多次。

private void Form1_load(object sender,EventArgs e)
{
	//也可以设置Form1窗体的IsIsMdiContainter属性为true 
	this.IsMdiContainter=true; 
}

private void ToolstripMenuItemToolbox_Click(object sender,EventArgs e)
{
	//"工具箱"的启动代码,实例化FormToolBox,并设置其Mdi父窗体为Form1 
	FormToolBox ftb=new FormToolBox();
	ftb.Mdiparent=this;
	ftb.show();
}

解决办法:
判断一下,这个FormToolBox有没有实例化就可以了
按了菜单的按钮时,再去FormToolBox ftb=new FormToolBox();这样就是实例化,这样我们把声明的工作放到全局变量来完成这样就解决了。

private  FormToolBox ftb;

private void ToolstripMenuItemToolbox_Click(object sender,EventArgs e)
{
	//判断是否实例化,如果为null说明没有实例化 
	if(ftb==null)
	{
		ftb=new FormToolBox();
		ftb.Mdiparent=this;
		ftb.Show();
	}
}

增加一个工具栏按钮的事件处理

//增加一个工具栏按钮的事件处理
private void toolStripButton1_Click(object sender,EventArgs e) 
{
	if(ftb==null)
	{
		ftb=new FormToolbox();
		ftb.MdiParent=this;
		ftb.Show();
	}	
}

当程序运行后,启动’工具箱’,在把’工具箱’ 窗体关闭,'工具箱’就不见了,因为它的实例没有变为null,而是disposed。所以还要增加disposed的判断

private void toolStripButton1_Click(object sender,EventArgs e) 
{
	if(ftb==null||ftb.Isdisposed)
	{
		ftb=new FormToolbox();
		ftb.MdiParent=this;
		ftb.Show();
	}	
}

单例模式:
保证一个类仅有一个实例,并提供一个访问它的全局访问点。
通常我们我们可以让一个全局变量使得一个对象被访问,但它不能防止你实例化多个对象。一个最好的办法是,让类自己负责保存它的唯一实例。这个类可以保证没有其他实例可以被创建,并且它可以提供一个访问该实例的方方法。

单例模式结构图

Singleton
-instance:Singleton()
-Singleton()
+GetInstance()

Singleton类,定义一个GetInstance,允许客户访问它的唯一实例。GetInstance是一个静态方法,主要负责创建自己的唯一实例。

class Singleton
{
	private static Singleton instance;
	//构造方法让其private,这就赌死了外界利用new创建此类实例的可能 
	private Singleton()
	{
		
	}
	//此方法是获得本类实例的唯一全局访问点 
	public static Singleton GetInstance()
	{
		//若实例不存在,则new一个新实例,否则返回已有的实例 
		if(instance==null)
		{
			instance=new Singleton();	
		}
		return instance;
	}
 } 


//客户端代码
static void main(string []args)
{
	Singleton s1=Singleton.GetInstance();
	Singleton s2=Singleton.GetInstance();
	//判断两次实例化的对象是结果相同 
	if(s1==s2)
	{
		Console.WriteLine("两个对象是相同的实例。");
		
	}
	Console.read();
}

单例模式的好处:
单例模式因为Singleton类封装它的唯一实例,这样它可以严格控制客户怎样访问它以及何时访问它。简单的说就是对唯一实例的受控访问。

多线程时的单例
问题:
在多线程同时,注意是同时访问Singleton类,调用GetInstance()方法,会有可能造成多个实例。

解决办法:
把进程交给一把锁处理。lock,是确保当一个线程位于代码的临界区时,另一个线程不进入临界区。如果其他线程想进入锁定的代码,则它一直等待(被阻止),直到对象被释放。

函数代码:

class Singleon
{
	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;
	}	
} 

这段代码让最先进入的那个线程创建对象实例以后的线程进入时不会再去创建对象实例了。由于有了lock,就保证了多线程环境下的同时访问也不*会造成多个实例的生成

双重锁定:

class Singleon
{
	private static Singleton instance;
	//程序运行时创建一个静态只读的进程辅助对象 
	private static readonly object syncroot=new object();
	private Singleton(){}
	public static Singleton GetInstance()
	{
		//先判断实例是否存在,不存在再加锁处理 
		if(instance==null)
		{	
		    //在同一时刻加了锁的那部分程序只有一个线程可以进入 
		    lock(syncroot)
		    {
			    if(instance==null)
			    {
				    instance=new Singleton();
			    }
		
		    }
		}
		return instance;
	}	
} 

这段代码解决了不用让线程每次都加锁,而只是实例化未被创建的时候再加锁处理。同时也能保证多线程的安全。这种方法被称为双重锁定(double-check locking)。

问题:
外面已经有了判断了instance实例是否存在,为什么在lock里面还需要做一次instance实例是否存在的判断?
‘回答:
1.当instance存在的情况,就直接返回是可以的。
2.当instance为null,且同时有两个线程调用Getinstance()方法时,它们都要经过第一次instance==nul的判断。然后由于lock机制,两个线程只有一个进入,另一个在外边排队等待,必须要其中的一个进入并出来后,另一个进入。如果没有第二次的instance为null的判断,那么第一个线程创建了实例,第二个线程还是可以继续创建新的实例,这就没有实现单例。

单例模式有个两个模式:饿汉模式,懒汉模式。
1.饿汉模式:当instance变量标记readonly时,在静态初始化期间或者在类的构造函数中分配变量,这种静态初始化的方式是在自己被加载时就将自己被实例化。
2.懒汉模式:在第一次被引用时,把自己实例化。也就是,当程序第一次放访问单例模式实例时进行创建。

分析懒汉模式和饿汉模式:
饿汉式:静态初始化的方式,它是类一加载就实例化的对象,因此需要提前占用系统资源。空间换取时间
懒汉式:面临多线程访问的安全性问题,因此需要双重锁定确保安全。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值