【问题标题】:Multi threading in case of singleton class C#单例类 C# 中的多线程
【发布时间】:2017-04-16 05:59:26
【问题描述】:

我想知道在多线程的情况下单例是如何工作的。 假设 2 个线程输入实例化代码,如下面的代码所示,第一个线程输入实例化代码,它锁定该部分并继续其操作,直到另一个线程等待。 所以一旦第一个线程完成它的操作,第二个线程将进入实例化代码,现在我想知道谁负责释放锁,因为第一个线程已经完成了它的操作,第二个线程会创建新实例还是会共享第一个线程实例化???

代码:

public sealed class Singleton
{
    private static Singleton instance = null;
    // adding locking object
    private static readonly object syncRoot = new object();
    private Singleton() { }

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

【问题讨论】:

  • 如果适用,考虑使用依赖注入而不是单例。容器实例化所有应该具有单个对象的类,并且这些类通过 ctor 注入到需要它们的类中。 Unity 是一个在 C# 中支持此功能的框架

标签: c#


【解决方案1】:

一旦第一个线程完成它的操作,第二个线程将进入实例化代码,现在我想知道谁负责释放锁,因为第一个线程已经完成了它的操作

每个线程单独获取和释放锁。第一个线程获取锁;虽然它有锁,但第二个线程无法获取它。

一旦第一个线程释放了锁(当执行离开由lock 语句控制的代码块时发生),第二个线程就可以获取锁并执行代码。完成后,它将再次释放锁。

...第二个线程会创建新实例还是共享第一个线程实例化???

在这个特定的实现中,单例只初始化一次,即使第二个线程最初观察到支持字段是null。通过使用lock,代码确保只有一个线程会真正创建单例实例。

可能会发生不止一次初始化,但恕我直言,这些都是较差的方法。

也就是说,就此而言,我认为在 .NET 的上下文中,即使是上面的双锁也是不必要的复杂。在大多数情况下,使用简单的字段初始化程序就足够了。在效率不够高的情况下,可以使用Lazy<T> 类。

如需更深入的讨论,请参阅相关的 Stack Overflow 问题 Thread Safe C# Singleton Pattern 以及那里提供的参考资料。

【讨论】:

    【解决方案2】:

    实现这一点的更好方法是我们可以创建一个静态构造函数。

    【讨论】:

      【解决方案3】:

      您在此处使用的称为双重检查锁定,这是一种相当常见的多线程代码序列化模式。它有效。

      一旦超出lock 范围,就会自动释放锁。

      假设存在争用,一个线程会 test->acquire->test->initialize->release,而下一个线程会简单地 test->acquire->test->release: no double-initialization。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-06-02
        • 1970-01-01
        • 2012-08-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多