多线程的程序中,多个线程同时,注意是同时访问Singleton类,调用GetInstance()方法,会有可能造成多个实例的。这个时候需要给进程加锁来处理
Singleton类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Singleton_Model
{
class Singleton
{
//私有化一个自己引用
private static Singleton instance;
//程序运行时候创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
//私有化构造器 杜绝了外界利用New实例化本类的可能
private Singleton()
{
}
//此方法是获得本类实例的唯一全局访问点
public static Singleton GetInstance()
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
return instance;
}
}
}
缺点:每次调用Instance都需要Lock会很耗费性能
新的Singleton类
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Singleton_Model
{
class Singleton
{
//私有化一个自己引用
private static Singleton instance;
//程序运行时候创建一个静态只读的进程辅助对象
private static readonly object syncRoot = new object();
//私有化构造器 杜绝了外界利用New实例化本类的可能
private Singleton()
{
}
//此方法是获得本类实例的唯一全局访问点
public static Singleton GetInstance()
{
if (instance==null)
{
lock (syncRoot)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
}
}
这里可以看到里外两层判断!没错这里没有问题 !当Instance为null并且同时有两个线程调用GetInstance方法时,它们都将可以通过第一重的Instancenull的判断,然后由于Lock机制,这两个线程则只能有一个进入 另一个排队等候。此时若是没有第二重的Instancenull的判断,则第一个线程创建了实例,而第二个线程还是可以继续再创建新的实例,这样就没有达到单例的目的!!
静态初始化:其实在实际的应用当中,C#与公共语言运行库也提供了一种‘静态初始化’的方法,这种方法不需要开发人员显示的编写线程安全的代码,即可以解决多线程环境下它不是安全的问题!实现更简单,但是谈不上更好!
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Singleton_Model
{
//sealed阻止发生派生,而派生可能会增加实例。
public sealed class Singleton1
{
private static readonly Singleton1 instance = new Singleton1();
private Singleton1()
{
}
public static Singleton1 GetInstance()
{
return instance;
}
/**
*
* * 这样的实现与前面的实例类似,也是解决了单例模式试图解决的两个基本问题,全局访问和实例化控制,
* 1 公共静态属性为访问实例提供了一个全局的访问点。
* 不同之处在于它依赖公共语言运行库来初始化变量。由于构造方法是私有的,因此不能再类本身以外实例化
* Singleton1类。因此 变量引用的是可以在系统中存在的唯一的实例。不过要注意,instance变量标记为readonly
* 这意味着只能在静态初始化期间或在类构造函数中分配【MSDN】。
* 由于这种静态初始化的方式是在自己被加载时就将自己实例化 所以形象的称为饿【汉式单例模式】
* 原先的单例处理模式是要再第一次被引用时,才会将自己实例化 所以被形象称为【懒汉单例模式】
* 【汉式单例模式】 静态初始化方式,它是类一加载就实例化的对象,所以要提前占用系统资源
* 【懒汉单例模式】 面临着多线程访问的安全问题 需要做双重锁定才能保证安全。
* 所以要用哪一种 必须考虑实际的需求 C#【汉式单例模式】基本能满足需求
*/
}
}
这样的实现与前面的实例类似,也是解决了单例模式试图解决的两个基本问题,全局访问和实例化控制,
* 1 公共静态属性为访问实例提供了一个全局的访问点。
* 不同之处在于它依赖公共语言运行库来初始化变量。由于构造方法是私有的,因此不能再类本身以外实例化
* Singleton1类。因此 变量引用的是可以在系统中存在的唯一的实例。不过要注意,instance变量标记为readonly
* 这意味着只能在静态初始化期间或在类构造函数中分配【MSDN】。
* 由于这种静态初始化的方式是在自己被加载时就将自己实例化 所以形象的称为饿【汉式单例模式】
* 原先的单例处理模式是要再第一次被引用时,才会将自己实例化 所以被形象称为【懒汉单例模式】
* 【汉式单例模式】 静态初始化方式,它是类一加载就实例化的对象,所以要提前占用系统资源
* 【懒汉单例模式】 面临着多线程访问的安全问题 需要做双重锁定才能保证安全。
* 所以要用哪一种 必须考虑实际的需求 C#【汉式单例模式】基本能满足需求