设计模式-单例

2017-12-21  本文已影响0人  不停雨

含义

注意

非线程安全

是否依赖初始化 : 是
是否多线程安全 : 否
总结 :
这种方式是最基本的实现方式,这种实现最大的问题就是不支持多线程。因为没有加锁 synchronized,所以严格意义上它并不算单例模式。
这种方式 lazy loading 很明显,不要求线程安全,在多线程不能正常工作。
e.g.

public class Singleton {
      private static Singleton instance;
      /// <summary>
      /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
      /// </summary>
      public static Singleton getInstance() {
            // 如果类的实例不存在则创建,否则直接返回
            if(instance == null) {
                  instance = new Singleton();
            }
            return instance;
      }
      private Singleton () { }
}

Unity3d 中e.g.

public class Singleton {
      private static Singleton instance;
      private void Awake () 
      {
            instance = this;
      }
      private Singleton () { }
}

简单安全线程

是否依赖初始化 : 是
是否多线程安全 : 是
总结 :
上述实现是线程安全的。这个线程在共享的object上取出了一把锁,然后在创建实例以前检查这个实例是否被创建了。这个保护了内存屏障问题(lock保证了所有的读取操作是在LOCK获得以后发生的,所有的unlock保证了所有的写操作在lock 释放以后发生的),这样就保证了一个线程只能创建一个实例(每次只有一个线程在这段代码中运行),不巧的是,性能上来说,锁变成了每次都必须的当这个实例被响应的时候。
  注意除了在锁当中锁住typeof(Singleton)这种类型的以外,我锁住了一个静态私有的变量,对于这个类来说。如果是锁 的一个对象的话,其他的类可以进入并且锁住(比如Type)这样会造成性能风险的问题甚至死锁。

public class Singleton
    {
        private static Singleton uniqueInstance;
        private static readonly object locker = new object();
        private Singleton(){}
        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
            // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
            // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
            lock (locker)
            {
                // 如果类的实例不存在则创建,否则直接返回
                if (uniqueInstance == null)
                {
                    uniqueInstance = new Singleton();
                }
            }

            return uniqueInstance;
        }
    }

线程安全(双重锁定)

是否依赖初始化 : 是
是否多线程安全 : 是
总结 :

 public class Singleton
    {
        private static Singleton uniqueInstance;
        private static readonly object locker = new object();
        private Singleton(){}
        /// <summary>
        /// 定义公有方法提供一个全局访问点,同时你也可以定义公有属性来提供全局访问点
        /// </summary>
        /// <returns></returns>
        public static Singleton GetInstance()
        {
            // 当第一个线程运行到这里时,此时会对locker对象 "加锁",
            // 当第二个线程运行该方法时,首先检测到locker对象为"加锁"状态,该线程就会挂起等待第一个线程解锁
            // lock语句运行完之后(即线程运行完之后)会对该对象"解锁"
            // 双重锁定只需要一句判断就可以了
            if (uniqueInstance == null)
            {
                lock (locker)
                {
                    // 如果类的实例不存在则创建,否则直接返回
                    if (uniqueInstance == null)
                    {
                        uniqueInstance = new Singleton();
                    }
                }
            }
            return uniqueInstance;
        }
    }

线程安全且不需要锁

是否依赖初始化 : 否
是否多线程安全 : 是
总结 :

public class Singleton {  
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}  
上一篇 下一篇

猜你喜欢

热点阅读