【问题标题】:Lazy singleton in a multithreaded c# application多线程 C# 应用程序中的惰性单例
【发布时间】:2013-03-05 11:25:25
【问题描述】:

我正在开发一个使用 WCF Web 服务的多线程 c# 应用程序。与 web 服务的连接将有一个特定的超时,我们可以定义它,然后它会关闭。我正在寻找使用单例类存储与 Web 服务的连接。我正在尝试按如下方式获取实例:

CLazySingleton ins = CLazySingleton.Instance;
string connection = CLazySingleton.abc;

下面是单例类的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LazySingleton
{
    public class CLazySingleton
    {
        private static readonly Lazy<CLazySingleton> _instance
            = new Lazy<CLazySingleton>(() => new CLazySingleton());
        private static readonly object ThreadLock = new object();
        public static string abc;  
        //I will use the service connection object in place of 'abc' in the application
        //assume that 'abc' is storing the connection object    

        private CLazySingleton()
        { }

        public static CLazySingleton Instance
        {
            get
            {   
                if (abc == null)
                {
                    lock (ThreadLock)
                    {
                        //Make the connection
                        abc = "Connection stored in this variable";
                        Console.WriteLine("Connection Made successfully");
                        return _instance.Value;
                    }                    
                }
                else
                {
                    return _instance.Value;
                }
            }
        }
    }
}

我的问题是: 1. 这段代码是否能够处理多个线程同时尝试获取实例?这是我目前最大的担忧。 2. 我能有更好的解决方案吗? 3.我需要在这里使用'lock'还是使用Lazy方法来处理试图获取实例的多线程?

任何帮助将不胜感激。

谢谢!

【问题讨论】:

  • 我对你的方法有些怀疑。为什么需要为连接维护一个 Singleton?如果每个线程都有自己的代理/连接,会有问题吗?而且由于它是一项网络服务,因此如果您创建许多连接,我预计不会出现任何问题。 --- 为了更好地理解什么是你的“连接”对象?
  • 你不需要锁

标签: c# .net multithreading wcf singleton


【解决方案1】:

根据 Microsoft 的 Lazy Initialization 文档,在标题为“线程安全初始化”的部分下:

默认情况下,Lazy 对象是线程安全的。

考虑到这一点,您的 abc 字段不必是静态的。当您使用 Lazy&lt;T&gt; 实例化您的单例时,在 CLazySingleton 构造函数中初始化您的连接是安全的。

【讨论】:

  • 嗨,理查德,感谢您的回复。你提出了一个很好的观点。甚至我也在思考同样的问题。但我的问题是,如果我在构造函数中编写建立连接的逻辑,我将如何管理连接在指定超时后自行过期的情况。在这种情况下,字段 abc 将变为 null 并且单例类将继续将其返回为 null ,因为不会再次调用构造函数。我希望我能表达我的观点。
  • 我认为在这里使用 Singleton 不是正确的模式,实际上您不需要以这种方式管理您的连接。而且,您确定要调用 Web 服务,因为您在这里提到的超时类型是什么?
【解决方案2】:

这段代码能否处理多个线程同时尝试获取实例?

在您的场景中,可以将“abc”字段初始化两次。想象一下情况,“abc”变量为空。第一个线程将在值分配之前位于“锁定”块内。第二个线程将在锁之前等待。因此,第一个线程将初始化“abc”,第二个线程将重新初始化它(您对 null 的检查超出了锁定范围,这就是原因)。但也许这不是你应该害怕的。

我能有更好的解决方案吗?

是的,你可以。让我在这个答案的最后一块描述它。

我需要在这里使用“锁定”还是使用惰性方法来处理试图获取实例的多线程?

在 Lazy 类中创建 Value 属性是线程安全的。在您的场景中,我将使用 Lazy 类的属性 IsValueCreated 的优势。您仍然需要 ThreadLock 对象。还有一件事是,一旦您访问 Lazy 类的 Value 属性, IsValueCreated 属性将返回 true (这就是技巧 ;-) )

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace LazySingleton
{
    public class CLazySingleton
    {
        private static readonly Lazy<CLazySingleton> _instance
            = new Lazy<CLazySingleton>(() => new CLazySingleton());
        private static readonly object ThreadLock = new object();
        public static string abc;  
        //I will use the service connection object in place of 'abc' in the application
        //assume that 'abc' is storing the connection object    

        private CLazySingleton()
        { }

        public static CLazySingleton Instance
        {
            get
            {   
                if (_instance.IsValueCreated)
                {
                    return _instance.Value;
                }
                lock (ThreadLock)
                {
                    if (abc == null)
                    {
                        abc = "Connection stored in this variable";
                        Console.WriteLine("Connection Made successfully");
                    }
                }
                return _instance.Value;
            }
        }
    }
}

【讨论】:

    【解决方案3】:

    简单使用ThreadSafetyMode

     Lazy<MergeSort> ty = new Lazy<MergeSort>(LazyThreadSafetyMode.ExecutionAndPublication);
    

    【讨论】:

    • Lazy 的默认构造函数使用 LazyThreadSafetyMode.ExecutionAndPublication,默认是线程安全的。
    • 谢谢,我一定会试试的。
    猜你喜欢
    • 2010-09-05
    • 2017-11-12
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 2013-05-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多