欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  科技

2020-11-11

程序员文章站 2022-07-10 17:45:15
C#设计模式(1)——单例模式一、单例模式的优缺点1.单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。2.单例模式的缺点就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。用单例模式,就是在适用其优点的状态下使用。二、单例模式的简介什么是单例模式?从“单例”字面意思上理解为—一个类只有一个实例,所以单例模式也就是保证一个类只有一个实例的一种实现方...

单例模式的理解与实现
一、单例模式的优缺点
1.单例模式只允许创建一个对象,因此节省内存,加快对象访问速度,因此对象需要被公用的场合适合使用,如多个模块使用同一个数据源连接对象等等。
2.单例模式的缺点就是不适用于变化的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的错误,不能保存彼此的状态。
用单例模式,就是在适用其优点的状态下使用。
二、单例模式的简介
什么是单例模式?从“单例”字面意思上理解为—一个类只有一个实例,所以单例模式也就是保证一个类只有一个实例的一种实现方法罢了。(设计模式其实就是帮助我们解决实际开发过程中的方法,该方法是为了降低对象之间的耦合度,然而解决方法有很多种,所以前人就总结了一些常用的解决方法为书籍,从而把这本书就称为设计模式)。
单例模式的官方定义:确保一个类只有一个实例,并提供一个全局访问点。
单例模式的一般实现为:
Singleton类通过定义一个私有变量uniqueInstance来记录单例类的唯一实例;
私有方法Singleton()来防止外界使用new关键字来创建该类实例;
公有方法GetInstance()来提供该类实例的唯一全局访问点。
public class Singleton
{
//私有变量来记录Singleton的唯一实例
private static Singleton uniqueInstance;
//私有构造函数
private Singleton()
{}
//定义公有方法来提供该类的唯一全局访问点
public static Singleton GetInstance()
{
//如实例不存在,则new一个新实例,否则返回已有实例
if(uniqueInstance == null)
{
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
上面的单例模式的实现在单线程下确实是完美的,然而在多线程的情况下会得到多个Singleton实例,因为在两个线程同时运行GetInstance方法时,此时两个线程判断(uniqueInstance == null)这个条件时都返回真,此时两个线程就都会创建Singleton的实例,这样就违背了我们单例模式初衷了,既然上面的实现会运行多个线程执行,那我们对于多线程的解决方案自然就是使GetInstance方法在同一时间只运行一个线程就好了,也就是我们线程同步的问题了,具体解决多线程的代码如下:
//单例模式的实现
public class Singleton
{
//定义一个静态变量来保存类的实例
private static Singleton uniqueInstance;

//定义一个标识,确保线程同步
private static readonly object locker = new object();

//定义私有构造函数,使外界不能创建该类实例
private Singleton()
{}

//定义公有方法提供一个全局访问点,同时也可以定义公有属性来提供全局访问点
public static Singleton GetInstance()
{
	//当第一线程运行到这里时,此时会对locker对象“加锁”,
	//当第二个线程运行该方法时,首先检测到locker对象为“加锁”状态,该线程就会挂起等待第一个线程解锁
	//locker语句运行完之后(即线程运行完之后)会对该对象“解锁”
	lock(locker)
	{
		//如果类的实例不存在则创建,否则直接返回
		if(uniqueInstance == null)
		{
			uniqueInstance = new Singleton();
		}
	}
		return uniqueInstance;
}

}

上面这种解决方案确实可以解决多线程的问题,但是上面代码对于每个线程都会对线程辅助对象locker加锁之后再判断实例是否存在,对于这个操作完全没有必要的,因为当第一个线程创建了该类的实例之后,后面的线程此时只需要直接判断(uniqueInstance == null)为假,此时完全没必要对线程辅助对象加锁之后再去判断,所以上面的实现方式增加了额外的开销,损失了性能,为了改进上面实现方式时缺陷,只需要在lock语句前面加一句(uniqueInstance == null)的判断就可以避免锁所增加的额外开销,这种实现方式就叫它“双重锁定”,下面具体看看实现的代码:
//单例模式的实现
public class Singleton
{
//定义一个静态变量来保存类的实例
private static Singleton uniqueInstance;

//定义一个标识确保线程同步
private static readonly object locker = new object();

//定义私有构造函数,使外界不能创建该类实例
private Singleton()
{}

//定义公有方法提供一个全局访问点,同时也可以定义公有属性来提供全局访问点
public static Singleton GetInstance()
{
	//当第一个线程运行到这里时,此时会对locker对象“加锁”,
	//当第二个线程运行该方法时,首先检测到locker对象为“加锁”状态,该线程就会挂起等待第一个线程解锁
	//lock语句运行完成之后(即线程运行完之后)会对该对象“解锁”
	//双重锁定只需一句判断就可以了
	if(uniqueInstance == null)
	{
		lock(locker)
		{
			if(uniqueInstance == null)
			{
				uniqueInstance = new Singleton();
			}
		}
	}
	return uniqueInstance;
}

}

本文地址:https://blog.csdn.net/m0_44998503/article/details/109611624