单例模式(饿汉式和懒汉式)

单例模式的定义


 

对系统中的某些类来说,只有一个实例很重要。例如游戏中Player角色类,玩家角色必须唯一。定义全局变量可以确保对象随时都可以被访问,但不能防止我们实例化多个对象。为了解决该问题,提出了让类自身负责保存它唯一实例。这个类保证没有其他实例被创建,并提供一个访问该实例的方法,这就是单例模式的思路。

单例模式(Singleton Pattern)确保某一个类只有一个实例,而自行实例化并向整个系统提供这个实例,这个类被称为单例类,它提供全局访问的方法。它是一种对象创建型模式。

  • 单例类只能有一个实例
  • 单例类必须自行创建这个实例
  • 单例类必须自行向整个系统提供这个实例

模式结构


 

单例模式实现过程必须:

  • 单例类构造函数为私有
  • 提供一个自身的静态私有变量
  • 提供一个公有的静态工厂方法

结构如下:

单例模式的缺点


 

  1. 单例模式没有抽象层,很难对其扩展
  2. 单例类职责过重,违背了“”单一职责原则“”

 饿汉式和懒汉式


1.饿汉式

class  Singleton
{
    private static Singleton _instanceSingleton = new Singleton();

    private Singleton()
    {
    //私有构造
    }

    public static Singleton getInstance()
    {
        return _instanceSingleton;
    }
}
class Program
{
    static void Main(string[] args)
    {
        Singleton XiaoHua  = Singleton.getInstance();
    }
}   

2、懒汉式

 1 class  Singleton
 2 {
 3     private static Singleton _instanceSingleton;
 4 
 5     private Singleton()
 6     {//私有构造
 7     }
 8 
 9     public static Singleton getInstance()
10     {
11         if (_instanceSingleton ==null)
12         {
13          _instanceSingleton = new Singleton();
14         }
15         return _instanceSingleton;
16     }
17 }
18 class Program
19 {
20     static void Main(string[] args)
21     {
22         Singleton XiaoHua  = Singleton.getInstance();
23     }
24 }        


比较上面两种写法:

从效率上看:

一个判断一个不判断,判断的浪费时间,但节省空间。不判断的浪费空间,但节省时间。从某种角度优先考虑使用饿汉式。

懒汉式是牺牲时间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间。

饿汉式选择牺牲空间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间。

从线程安全上看:

不加同步的懒汉式是线程不安全的。假设有两个线程,一个是线程A,一个是线程B,它们同时调用getInstance方法,那就可能导致并发问题,出现两个实例。解决方法可以通过双重检查锁定(Double-CheckLocking)的双重判断机制。

  1. 当实例不存在且同时有两个线程调用GetInstance()方法时,它们都可以通过第一重“_instanceSingleton == null”判断
  2. 然后由于lock锁定机制,只有一个线程进入lock中执行创建代码,另一个线程处于排队等待状态
  3. 必须等待第一个线程执行完毕后才可以进入lock锁定的代码
  4. 进行第二重“_instanceSingleton == null”判断,是否创建实例

最终改良后的懒汉式:

class Singleton
{
    private static Singleton _instanceSingleton;
        
    //程序运行时创建一个静态只读的辅助对象  
    private static readonly object syncRoot = new object();


    private Singleton()
    {//私有构造
    }

    public static Singleton getInstance()
    {
        if (_instanceSingleton == null)
        {
            lock (syncRoot)//线程控制
            {
                if(_instanceSingleton == null){
                
                _instanceSingleton = new Singleton();                
                
                }      
            }
        }
        return _instanceSingleton;
    }
}
class Program
{
    static void Main(string[] args)
    {
        Singleton XiaoHua = Singleton.getInstance();
    }
}        

 

posted @ 2017-07-28 23:29  20世纪少年  阅读(773)  评论(0编辑  收藏  举报