简体   繁体   English

为什么单例模式的这种实现可以有两个实例

[英]Why this realization of Singleton Pattern can have two instances

I am learning Singleton Pattern. 我正在学习Singleton模式。 On msdn the first realization of Singleton Pattern is: 在msdn上,单例模式的第一个实现是:

public class Singleton
{
   private static Singleton instance;

   private Singleton() {}

   public static Singleton Instance
   {
      get 
      {
         if (instance == null)
         {
            instance = new Singleton();
         }
         return instance;
      }
   }
 public void Display()
    {
        Console.WriteLine("This is from Singleton!");
    }
}

The main disadvantage of this implementation, however, is that it is not safe for multithreaded environments. 但是,此实现的主要缺点是它对多线程环境不安全。 If separate threads of execution enter the Instance property method at the same time, more that one instance of the Singleton object may be created. 如果单独的执行线程同时输入Instance属性方法,则可能会创建Singleton对象的一个​​以上实例。

I tried to create two instances of this class: 我试图创建该类的两个实例:

Console.WriteLine("First Instance!");
Singleton s = Singleton.Instance;
s.Display();

Console.WriteLine("Second Instance!");
Singleton ss = Singleton.Instance;
ss.Display();

Console.ReadLine();

Both "s" and "ss" are created so I guess I misunderstand something. 都创建了“ s”和“ ss”,所以我想我误会了一些东西。 Can you please let me know why two instances are created? 您能否让我知道为什么要创建两个实例?

In this case you are not creating two instances. 在这种情况下,您不会创建两个实例。 Instead you create two variables pointing to the same instance. 而是创建两个指向同一实例的变量。 The first call Singleton s = Singleton.Instance; 第一次调用Singleton s = Singleton.Instance; creates the instance. 创建实例。 The second call just gives back the same instance. 第二个调用只返回相同的实例。 If you give the singleton class another field (lets call it string text) and then call s.text = "a"; 如果为单例类提供另一个字段(将其称为字符串文本),然后调用s.text = "a"; ss.text will also have the value "a"; ss.text也将具有值“ a”;

To make the whole thing thread safe you could take a look at the Mutex class for example. 为了使整个线程安全,您可以看一下Mutex类。

In the code segment, if(instance == null) check will be fine to create single instance of the class only if the module is accessed by single thread always. 在代码段中,仅当始终由单线程访问模块时, if(instance == null)检查才可以创建类的单个实例。

But in case of multiple threaded environment, it will fail and will be resulted in multiple instance of the Singleton Class. 但是在多线程环境下,它将失败并导致Singleton类的多个实例。

Say T1 and T2 are two threads which are accessing the get method simultaneously at some moment. 假设T1和T2是两个线程,它们正在同时访问get方法。

get 
{
    if (instance == null)
    {
        instance = new Singleton();
    }
    return instance;
}

The explanation is as below: 解释如下:

  1. When T1 executes if(instance == null) , and enters inside if block if instance is not yet initialized. 当T1执行if(instance == null) ,如果实例尚未初始化,则进入if块内部。
  2. At the same time, if T2 also executes if(instance == null) line, just when T1 enters the block (T1 is yet to execute instance = new Singleton() ) 同时,如果T2也执行if(instance == null)行,就在T1进入块时(T1尚未执行instance = new Singleton()
  3. Both the threads will be allowed inside if block. if阻塞,两个线程都将被允许进入。
  4. Both threads will be able to create two difference instances of Singleton Class. 两个线程将能够创建两个不同的Singleton类实例。

The correct way to work with multiple threads here will be as below- 在这里使用多个线程的正确方法如下:

get 
{
    if (instance == null)
    {
        lock();
        if (instance == null)
        {
            instance = new Singleton();
        }
        unlock();
    }
    return instance;
}

Two (or even more) separate threads can get to if (instance == null) check at same time. 两个(甚至更多个)单独的线程可以同时进行if (instance == null)检查。 Both checks will return true if instance not exists yet. 如果实例尚不存在,则两个检查都将返回true Then both threads will go further, and each will create its own instance of class. 然后,两个线程将走得更远,每个线程将创建自己的类实例。

Solution: Double-checked locking 解决方案: 双重检查锁定

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM