简单的单例模式
Posted zhangxianshen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了简单的单例模式相关的知识,希望对你有一定的参考价值。
简单的单例模式
单例模式是现在最常用的软件设计模式,也是最简单设计模式,通过单例模式可以保证系统中,这个类只有一个实例
假如在下面这种情况下,我们有一个数据库连接类,在平常的时候,我们实例化这个类然后写入连接,第一次我链接了SQLServer数据库,第二次我链接了mysql数据库,但是我同时想用这两个数据库,发现不太合适,就需要一个方法方式来解决问题,这是最适合用单例模式了
虽然我举的栗子可能不太合适,但是大概就是这么一个意思,保证只有一个实例,避免多个实例不知道使用哪个或者多个实例导致报错
使用
单例模式要求类能够返回一个对象的引用和一个获得该实例的方法,静态的方法
实现主要是有两个步骤:
①:经该类的构造函数定义为私有的(private)
②:在这个类里提供一个静态方法
在这里要区别的是单例模式有两种:恶汉模式和懒汉模式
恶汉模式是在项目运行起来就实例化了这个类
懒汉模式是在需要这个类的时候才实例化这个类
先不多说了,上代码:
这个是恶汉模式:
/// <summary>
/// 单例模式的实现
/// </summary>
public class SingletonEh
{
// 定义一个静态变量来保存类的实例
private static SingletonEh uniqueInstance=new SingletonEh();
private SingletonEh()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static SingletonEh GetInstance()
{
return uniqueInstance;
}
}
这个是不安全的懒汉模式:
/// <summary>
/// 单例模式线程不安全的实现(懒汉模式)
/// </summary>
public class SingletonThread
{
// 定义一个静态变量来保存类的实例
private static SingletonThread uniqueInstance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private SingletonThread()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static SingletonThread GetInstance()
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new SingletonThread();
}
return uniqueInstance;
}
}
大家可能注意到了我说的是不安全的懒汉模式,别急,这就来解释,在懒汉模式中,如果单线程的话没问题,如果是多线程呢,加入同时两个线程需要使用这个类,通过代码可以看到,都通过判断,都实例化了这个类,那就没有单例模式的意义了,既然有问题就有解决办法,下面这个是线程安全的单例模式,加锁的单例模式
/// <summary>
/// 单例模式线程安全的实现(懒汉模式)
/// </summary>
public class SingletonThread
{
// 定义一个静态变量来保存类的实例
private static SingletonThread uniqueInstance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private SingletonThread()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static SingletonThread GetInstance()
{
// 当第一个线程运行到这里时,此时会对locker对象 "加锁",
// 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
// lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
lock (locker)
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new SingletonThread();
}
}
return uniqueInstance;
}
}
这很安全了,但是,每次使用我都得等上一个任务完成解锁后才可以继续,这就造成了可能排老长的队,也不太合适,那么,咱们继续优化一下
/// <summary>
/// 优化后的单例模式线程安全的实现(懒汉模式)
/// </summary>
public class SingletonThreadOptimize
{
// 定义一个静态变量来保存类的实例
private static SingletonThreadOptimize uniqueInstance;
// 定义一个标识确保线程同步
private static readonly object locker = new object();
// 定义私有构造函数,使外界不能创建该类实例
private SingletonThreadOptimize()
{
}
/// <summary>
/// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
/// </summary>
/// <returns></returns>
public static SingletonThreadOptimize GetInstance()
{
// 当第一个线程运行到这里时,此时会对locker对象 "加锁",
// 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
// lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
// 双重锁定只需要一句判断就可以了
if (uniqueInstance == null)
{
lock (locker)
{
// 如果类的实例不存在则创建,否则直接返回
if (uniqueInstance == null)
{
uniqueInstance = new SingletonThreadOptimize();
}
}
}
return uniqueInstance;
}
}
优点
系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能。
缺点
当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new,可能会给其他开发人员造成困扰,特别是看不到源码的时候
以上是关于简单的单例模式的主要内容,如果未能解决你的问题,请参考以下文章