单例模式

1.定义

  单例模式保证一个类仅有一个实例,并提供一个访问他的全局访问点。

  通常我们可以建立一个全局变量使得一个对象被多个类所访问,但是这样还是无法防止你多次实例化这个对象;这时候一个最好的方法就是:让类自身来负责保证他的唯一实例。这个类保证没有其他实例可以被创建,并且它可以提供一个访问自身实例的方法。

2.理解

  单例模式因为由类自己封装了它的唯一实例,这样就可以严格的控制客户怎样访问它及何时访问它;简单的说就是实现对唯一实例的受控访问。

  同时也要区别单例模式下的类和普通实用类的区别:实用类不保存状态,只提供一些静态的属性和方法让你使用,而单例类是有状态的;实用类不能用于继承多态,而单例类却可以由子类来继承;实用类只不过是一些方法、属性的集合,而单例类是有着唯一的对象实例。在具体使用时,需要根据需求来确定到底使用哪一种方式。

3.多线程下的单例模式

  在多线程下,为了保证仍然实现单例模式,需要给进程加一把锁来处理,即使用lock语句。

  lock的含义:lock是确保当一个线程位于代码的临界区域时,另一个线程不能进入临界区域。如果其他线程试图进入锁定的代码,则它将一直等待(即被阻止的意思),直到该对象区域被释放。具体代码如下:

 1 class Singleton
 2     {
 3         private static Singleton instance;
 4         //在程序运行时就创建一个静态只读的进程辅助对象[由于加锁时,程序是不知道instance有没有被创建过实例,
 5         //从而无法加锁,所以需要创建一个辅助对象]
 6         private static readonly object syncRoot = new object();
 7         private Singleton()
 8         {
 9 
10         }
11         /*下面这种方式,由于没有判断,会导致每一次调用此方法时都需要lock,因此会影响性能*/
12         public static Singleton GetInstance1()
13         {
14             lock (syncRoot)
15             {
16                 if (instance == null)
17                     instance = new Singleton();
18             }
19             return instance;
20         }
21 
22         /*所以需要“双重锁定”来改善*/
23         public static Singleton GetInstance2()
24         {
25             //第一个判断:实例是否存在,如果不存在则加锁处理
26             if (instance == null)
27             {
28                 lock (syncRoot)
29                 {
30                     //第二次判断:这里是为了实现单利模式(如果没有这个判断,那么多线程下就不能保证单例了)
31                     if (instance == null)
32                         instance = new Singleton();
33                 }
34             }
35             return instance;
36         }
37     }

4.扩展

  在实际应用中,C#与公共语言运行库也提供了一种单例模式的实现“静态初始化”,这种方式不需要开发人员显式的编写线程安全代码,即可解决多线程环境下单例模式的安全问题。如下面代码所示:

 1 /*阻止派生发生,因为派生可能会产生多个实例*/
 2     public sealed class Singleton
 3     {
 4         /*在加载类时就将自己实例化,由公共语言运行库负责执行;但是因为instance被标记为了只读,所以只能在静态初始化期间或者
在类的构造函数中分配变量
*/ 5 private static readonly Singleton instance = new Singleton(); 6 private Singleton() 7 { } 8 public static Singleton GetInstance() 9 { 10 return instance; 11 } 12 }

由这种方式又引出两种单例模式:

  饿汉式单例:由于这种方式下(静态初始化的方式),实在类自己被加载时就将自己实例化,所以被形象的成为饿汉式单例。

  懒汉式单例:在类被第一次引用时才会将自己实例化。

  区别:饿汉式单例由于在类加载时就已经实例化,因此会提前占用系统资源;而懒汉式又需要开发人员自己处理多线程环境下的安全问题,需要做双重锁定才可以保证安全。正常情况下,饿汉式单例已经可以满足我们的需求。

5、我的浅薄理解

  我的使用环境是:在一个窗体程序中,需要一个单独的类来记录一些环境状态(数据库连接、中间结果等),这就需要保证这个记录环境的类只能被实例化一次,然后其他类在使用时才可以访问已经保存的变量,所以用到了单例模式。通过一次使用下来我觉得,懒汉式的单例模式更加容易理解,还有就是因为我的程序是单线程的环境,并且要在不同的地方给环境变量赋值,所以觉得饿汉式单例的话变量没法赋值了,因此使用的是懒汉式单例模式(斯以为这种方式看起来也更加顺眼)。所以我的不成熟意见还是认为懒汉式单例更加易用一些。

posted @ 2016-10-23 18:16  花火灬流年  阅读(215)  评论(0编辑  收藏  举报