多线程c#应用程序中的懒惰单例

时间:2013-03-05 11:25:26

标签: c# .net multithreading wcf singleton

我正在开发一个使用WCF Web服务的多线程c#应用程序。与webservice的连接将具有我们可以定义的特定超时,然后它将关闭。我希望使用singleton类存储与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方法来处理试图获取实例的多线程?

任何帮助都将不胜感激。

谢谢!

3 个答案:

答案 0 :(得分:9)

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

  

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

考虑到这一点,您的abc字段不一定是静态的。当您使用Lazy<T>来实例化单例时,可以安全地在CLazySingleton构造函数中初始化连接。

答案 1 :(得分:5)

简单使用ThreadSafetyMode

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

答案 2 :(得分:4)

  

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

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

  

我可以为此提供更好的解决方案吗?

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

  

我是否需要在这里使用'lock'或者使用Lazy方法来处理尝试获取实例的多线程?

在Lazy类中创建Value属性是线程安全的。在您的场景中,我将使用属性IsValueCreated of Lazy&lt;&gt;类。您仍然需要ThreadLock对象。还有一件事是,一旦您访问Lazy&lt;&gt;的Value属性class,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;
            }
        }
    }
}