单件模式:(Singleton pattern)
1.目的
1) 在全局范围内控制一个对象只能有一个唯一的实例
2.作用
具体程序设计中往往需要保证一个类只能有一个实例
如:
一个客户端只能有一个数据库连接;
为了节省资源,配置文件只能被加载一次;
虽然又多个串行端口,但使能又一个COM1实例(比如对嵌入式编程,对外设开发驱动程序等等)
3.单件模式的机制
1) 单件模式保证只能常见对象的唯一一个实例
2) 单件模式提供一个全局访问点:(不让外边来创建实例,提供一个方法来获取我的实例,该方法就是全局的访问点)
3) 通过静态变量C#,Java中(static),VB中(Shared)来实现唯一性.(静态成员在全局范围内是唯一的不属于某个对象属于类)
4.多线程下的单件模式 (多线程下存在多线程同步的问题,如果不控制多线程同步,那么多线程同时访问单件模式这个方法,可能会生成不唯一的实例,所以需要控制多线程同步问题)
1) 在多线程下,保证一个类只有唯一一个实例
2) C#->lock,Java->synchronized
开始,结束.public static load()
3)为什么在多线程下可能会生成不唯一的实例呢?
假如有两个线程,同时访问GetInstances()这个方法,第一个线程执行到singleton = new Singleton();这行
第二个线程执行到 { 这行,很明显会产生两个实例了.
ClassDiagram:
SequenceDiagram:
单线程下的单例示例:
class Program { static void Main(string[] args) { Singleton single1 = Singleton.GetInstances(); Singleton single2 = Singleton.GetInstances(); //结果为ture,这样一个简单的单例模式就完成了!!! Console.WriteLine(single1==single2); Console.ReadKey(); } } /// /// 单线程下的单例模式 /// class Singleton { //用静态变量的目的是为了保证唯一性(静态变量是唯一的,在类中共享的不属于某个对象) public static Singleton singleton = null; private Singleton() { } //饿汉式写法.这种写法可能在多个线程访问事出现两个对象(虽然可能行很小!) public static Singleton GetInstances() { if (singleton==null) { singleton = new Singleton(); } return singleton; } }
class Client { static void Main(string[] args) { Singleton s1 = Singleton.GetInstance(); Singleton s2 = Singleton.GetInstance(); Console.WriteLine(s1 == s2); Console.ReadKey(); } } public class Singleton { //静态成员在类初始化时只会被加载一次. private static Singleton singleton = new Singleton(); //懒汉式写法(这种方式多线程下不会出现两个对象.) public static Singleton GetInstance() { return singleton; } }
多线程下的示例:
static void Main(string[] args) { Singleton single1 = Singleton.GetInstances(); Singleton single2 = Singleton.GetInstances(); //结果为ture,这样一个简单的单例模式就完成了!!! Console.WriteLine(single1 == single2); Console.ReadKey(); } } /// <summary> /// 单线程下的单例模式 /// </summary> class Singleton { //用静态变量的目的是为了保证唯一性(静态变量是唯一的,在类中共享的不属于某个对象) public static Singleton singleton = null; private Singleton() { } public static Singleton GetInstances() { //lock(同步)的作用:保证在lock代码块中的代码在同一时刻只能有同一个线程可以访问它 /*这和数据库的锁一个意思,通俗的讲当一个线程执行到lock里的代码块,第二个线程也来了 来了后被lock挡住,档在外面了,等第一个线程执行完以后,才去执行第二个线程(线程同步的概念) */ lock (typeof(Singleton)) { if (singleton == null) { singleton = new Singleton(); } return singleton; } } }
using System; using System.Collections; using System.Threading; // "Singleton" class LoadBalancer { // Fields private static LoadBalancer balancer; private ArrayList servers = new ArrayList(); private Random random = new Random(); // Constructors (protected) protected LoadBalancer() { // List of available servers servers.Add( "ServerI" ); servers.Add( "ServerII" ); servers.Add( "ServerIII" ); servers.Add( "ServerIV" ); servers.Add( "ServerV" ); } // Methods public static LoadBalancer GetLoadBalancer() { // Support multithreaded applications through // "Double checked locking" pattern which avoids // locking every time the method is invoked if( balancer == null ) { // 只允许一个线程访问 Mutex mutex = new Mutex(); mutex.WaitOne(); if( balancer == null ) balancer = new LoadBalancer(); mutex.Close(); } return balancer; } // Properties public string Server { get { // Simple, but effective random load balancer int r = random.Next( servers.Count ); return servers[ r ].ToString(); } } } /** <summary> /// SingletonApp test /// </summary> /// public class SingletonApp { public static void Main( string[] args ) { LoadBalancer b1 = LoadBalancer.GetLoadBalancer(); LoadBalancer b2 = LoadBalancer.GetLoadBalancer(); LoadBalancer b3 = LoadBalancer.GetLoadBalancer(); LoadBalancer b4 = LoadBalancer.GetLoadBalancer(); // Same instance? if( (b1 == b2) && (b2 == b3) && (b3 == b4) ) Console.WriteLine( "Same instance" ); // Do the load balancing Console.WriteLine( b1.Server ); Console.WriteLine( b2.Server ); Console.WriteLine( b3.Server ); Console.WriteLine( b4.Server ); } }
C#的独特语言特性决定了C#拥有实现Singleton模式的独特方法。这里不再赘述原因,给出几个结果:
方法一:
下面是利用.NET Framework平台优势实现Singleton模式的代码:
sealed class Singleton { private Singleton(); public static readonly Singleton Instance=new Singleton(); }
这使得代码减少了许多,同时也解决了线程问题带来的性能上损失。那么它又是怎样工作的呢?
注意到,Singleton类被声明为sealed,以此保证它自己不会被继承,其次没有了Instance的方法,将原来_instance成员变量变成public readonly,并在声明时被初始化。通过这些改变,我们确实得到了Singleton的模式,原因是在JIT的处理过程中,如果类中的static属性被任何方法使用时,.NET Framework将对这个属性进行初始化,于是在初始化Instance属性的同时Singleton类实例得以创建和装载。而私有的构造函数和readonly(只读)保证了Singleton不会被再次实例化,这正是Singleton设计模式的意图。
不过这也带来了一些问题,比如无法继承,实例在程序一运行就被初始化,无法实现延迟初始化等。
方法二:
既然方法一存在问题,我们还有其它办法。
public sealed class Singleton { Singleton() { } public static Singleton GetInstance() { return Nested.instance; } class Nested { // Explicit static constructor to tell C# compiler // not to mark type as beforefieldinit static Nested() { } internal static readonly Singleton instance = new Singleton(); } }
java示例:
public class Singleton {
private static Singleton instance = null;
public static synchronized Singleton getInstance() {
if (instance == null){
instance = new Singleton();
}
return instance;
}
}