单一模式中的双重检查锁定

时间:2011-05-10 13:01:15

标签: c#

这可能是基本问题

要在多线程环境中使用单例,我们可以使用锁。请参阅代码段。但为什么我们需要在单件模式中进行双重检查锁定?更多的是双重检查锁定意味着什么?

class singleton
{
    private static singleton instance = null;
    private static singleton() { }

    private static object objectlock = new object();

    public static singleton Instance
    {
        get
        {

            lock (objectlock) //single - check lock
            {
                if (instance == null)
                {
                    instance = new singleton();
                }

                return instance;
            }
        }

    }
}

6 个答案:

答案 0 :(得分:26)

Jon Skeet explains this in detail

锁很贵 如果对象已经存在,那么取出锁是没有意义的 因此,您可以在锁外进行第一次检查。

但是,即使在您查看之前该对象不存在,另一个线程也可能在if条件和lock语句之间创建它。 因此,您需要在锁内再次检查。

但是,编写单例的最佳方法是使用static构造函数:

public sealed class Singleton
{
    private Singleton()
    {
    }

    public static Singleton Instance { get { return Nested.instance; } }

    private class Nested
    {
        // Explicit static constructor to tell C# compiler
        // not to mark type as beforefieldinit
        static Nested()
        {
        }

        internal static readonly Singleton instance = new Singleton();
    }
} 

答案 1 :(得分:5)

使用.Net 4.x和更新版本时,您应尽可能遵循Lazy类,因为此模式与“初始化和发布”选项一起使用。 (注意:逆也可用,其中创建不是线程安全的,但实例的发布是通过Publication选项发布的)

答案 2 :(得分:3)

我所知道的“最佳”方式是:

public class MySingleton {
    // object for synchronization
    private static readonly object syncRoot = new object();
    // the singleton instance
    private static MySingleton @default;

    public static MySingleton Default {
        get {
            // geting singleton instance without locking
            var result = @default;
            // if result is NOT null, no additional action is required
            if ( object.ReferenceEquals(result, null) ){
                // lock the synchronization object
                lock(syncRoot) {
                    // geting singleton instanc in lock - because
                    // the value of @default field could be changed
                    result = @default;

                    // checking for NULL
                    if ( object.ReferenceEquals(result, null) ) {
                        // if result is NULL, create new singleton instance
                        result = new MySingleton();
                        // set the default instance
                        @default = result;
                    }
                }
            }

            // return singleton instance
            return result;
        }
    }
}

答案 3 :(得分:3)

多线程单例:使用双重检查锁定的最佳方法

public sealed class Singleton
{
   private static volatile Singleton _instance;
   private static readonly object InstanceLoker= new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (_instance == null) 
         {
            lock (InstanceLoker) 
            {
               if (_instance == null) 
                  _instance = new Singleton();
            }
         }

         return _instance;
      }
   }
}

答案 4 :(得分:2)

如果您在字段初始化程序中创建对象,则不需要锁定:

class singleton
{
    private static singleton instance = new singleton();
    private static singleton() { }

    public static singleton Instance
    {
        get { return instance; }
    }
}

另外 - 请记住锁只是控制对象的创建,如果你在多个线程中使用它,对象仍然需要是线程安全的。

答案 5 :(得分:2)

当我们尝试使用Parallel库执行singleton类的方法时。它不能识别单例行为,因为在TPL中执行多线程会导致概念Singleton Pattern失败。为了克服这个问题,存在锁定对象的概念,使得一次只有一个线程可以访问它。 但这不是有效的方法,因为锁定检查的参与会对对象产生不必要的监视。为了避免它,我们使用“双重锁定检查”

enter image description here