C#中的单例线程安全 - 为什么要添加双重检查?

时间:2012-05-10 23:35:27

标签: c# design-patterns locking thread-safety singleton

using System;

public sealed class Singleton
{
   private static volatile Singleton instance;
   private static object syncRoot = new Object();

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null) 
         {
            lock (syncRoot) 
            {
               if (instance == null) 
                  instance = new Singleton();
            }
         }

         return instance;
      }
   }
}

我不明白为什么要仔细检查! 我读到这个双重检查是为了解决线程并发问题 - 但是......

  1. 锁将解决它 - 所以我们需要首先'if'

  2. 如果这个单例没有第一个'if'它仍然是线程安全的 - 对吧?

  3. 如果第一个'if'为false - 那么thread1将初始化'instance'object =>现在,'instance'不为null并且thread1仍然在锁定块中===>>现在,thread2检查第一个'if'并将得到false =>所以他不会进入'lock'并且迫切地将返回实例并且thread2能够改变'instance'=>的属性。所以thread1&& thread2在同一'instance'object =>上'工作'那么线程安全在哪里......或者我在这里缺少的东西。

4 个答案:

答案 0 :(得分:6)

  

1.锁将解决它 - 所以我们需要首先'如果'

所以除非你需要创建Singleton的新实例,否则你不会锁定thred lock非常昂贵的操作,因此值得进行额外检查。

  

2.如果这个单例将没有第一个'if',它仍然是线程安全的 - 对吗?

是的,但速度要慢得多。

  

3.Thread1&& thread2在同一'instance'object =>上'工作'那么线程安全在哪里

这是单例的全部要点,所有线程只有一个实例。那是线程安全的事情......

答案 1 :(得分:2)

我假设如果ThreadA在lock之前被中断; ThreadB成功完成单例的创建,然后当ThreadA恢复时,它将尝试在释放锁后重新创建单例。

答案 2 :(得分:0)

if检查单例是否已经实例化,如果它没有创建新的实例。锁定确保线程安全。

没有if它会在每次调用时创建一个新的instace(不是单例的想法)。如果没有锁定,两个线程就可以模拟地创建一个实例,因此可能存在两个实例。

如果您只使用单线程,则可以擦除锁定。否则(在mt上)强烈建议使用它。

答案 3 :(得分:0)

以下是马里兰大学关于推荐原因的一篇好文章(以及为什么它并不总是适用于现代优化编译器)如果你有时间,这是一本很好的读物。

http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html