2013-03-05 39 views
10

我正在使用消耗WCF Web服务的多线程c#应用程序。与web服务的连接将会有一个特定的超时时间,我们可以定义它,然后关闭。我正在寻找使用单例类存储连接到Web服务。我想获得实例如下:多线程c#应用程序中的懒惰单例

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.我是否需要在此处使用“锁定”或使用Lazy方法来处理尝试获取实例的多线程?

任何帮助,将不胜感激。

谢谢!

+1

看看这篇文章由乔恩斯基特。它在讨论Singleton模式方面做得很好。 http://www.yoda.arachsys.com/csharp/singleton.html – juharr 2013-03-05 11:29:14

+0

我对你的方法有些怀疑。为什么你需要维护一个单身人士的连接?如果每个线程都有自己的代理/连接,是否有问题?而且由于它是一项网络服务,如果您创建了许多连接,我不会预见到任何问题。 ---更好地理解你的“连接”是什么样的对象? – thewpfguy 2013-03-08 06:24:45

+0

你不需要锁 – Rafa 2014-02-14 15:55:24

回答

5

简单使用ThreadSafetyMode

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

懒惰的默认构造函数使用LazyThreadSafetyMode.ExecutionAndPublication,默认情况下它是线程安全的。 – Phil 2013-03-05 11:45:31

+0

谢谢,我一定会试试这个。 – 2013-03-05 15:29:08

8

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

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

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

+0

嗨Richard,谢谢你的回应。你说得很好。即使我也在思考这个问题。但我的问题是,如果我编写逻辑来在构造函数中建立连接,我将如何管理连接在指定的超时后自行失效的场景。在这种情况下,字段abc将变为null,并且单例类将继续返回为null,因为不会再次调用构造函数。我希望我能说出我的观点。 – 2013-03-05 15:15:20

+0

我认为使用Singleton在这里不是正确的模式,实际上你不需要这样管理你的连接。而且,您确定您正在调用Web服务,因为您在此提及的是什么类型的超时? – thewpfguy 2013-03-08 06:33:16

3

此代码是否能够照顾多个线程试图同时获取实例?

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

我可以有更好的解决方案吗?

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

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

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