4
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. 锁会解决它 - 那么为什么我们需要先“如果”

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

  3. 如果第一个 'if' 为 false - 那么 thread1 将初始化 'instance' 对象 => 现在,'instance' 不为 null 并且 thread1 仍在锁定块中 ===>> 现在,thread2 检查第一个' if' 并且会得到 false => 所以他不会到达'lock' 并且很快就会返回实例,并且 thread2 能够更改 'instance' => 所以 thread1 && thread2 在同一个'instance'上'工作' ' object => 那么线程安全在哪里......或者我在这里缺少什么。

4

4 回答 4

6

1.锁会解决它 - 那么为什么我们需要先“如果”

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

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

是的,但速度要慢得多。

3.Thread1 && thread2 在同一个“实例”对象上“工作”=> 那么线程安全在哪里

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

于 2012-05-10T23:41:32.367 回答
2

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

于 2012-05-10T23:42:46.697 回答
0

if 检查单例是否已经实例化,如果没有,则创建一个新实例。和锁确保线程安全。

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

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

于 2012-05-10T23:42:25.580 回答
0

这是来自马里兰大学的一篇很好的论文,关于为什么推荐它(以及为什么它在现代优化编译器中并不总是有效)如果你有时间,这是一本很好的读物。

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

于 2012-05-10T23:45:37.647 回答