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

本文关键字:添加 检查 为什么 单例 线程 安全 | 更新日期: 2023-09-27 18:33:45

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. 如果
  3. 这个单例没有第一个"如果",它仍然是线程安全的 - 对吧?

  4. 如果第一个"if"为假 - 所以 thread1 将初始化"实例"对象 => 现在,"实例"不为空,线程 1 仍在锁定块中 ===>> 现在,线程 2 检查第一个"如果"并将得到 false => 所以他不会到达"锁"并立即返回实例,线程 2 能够更改"实例"的属性 => 所以线程 1 &&线程 2 在同一个"实例"对象上"工作"=> 所以线程安全吗...或者我在这里错过了什么。

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

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

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

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

是的,但速度明显慢。

3.线程 1 &&线程 2 在同一个"实例"对象 => 上"工作",所以线程在哪里安全

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

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

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

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

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

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

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