1

我已经花了大约一个小时来寻找对我想要完成的事情的共识,但还没有在特定方向上找到任何结论性的东西。

我的情况如下:

  • 我有一个多线程应用程序(.NET Web 服务)
  • 我的类使用的对象加载时间不可忽略,所以我想将它们维护为静态类成员
  • 间歇性地构造这些对象的代码失败的可能性很低

我以前使用的方法是在静态构造函数中构造这些对象。问题在于,如上所述,构造函数偶尔会失败,并且一旦 .NET 静态构造函数失败,整个类都会被淹没,直到进程重新启动。这种方法没有第二次机会。

在此之后最直观的方法是使用双重检查锁定。周围有很多页面都在谈论双重检查锁定的弊端,并说要使用静态构造函数,我已经在这样做了,但这对我来说似乎不是一个选择,因为静态构造函数具有可能会失败并拖垮整个班级。

我正在考虑使用的实现(当然是简化的)如下。所有类名和成员名都纯粹是示范性的,而不是我实际使用的。这种方法会不会有问题?任何人都可以提出更好的方法吗?

public class LazyMembers
{
    private static volatile XmlDocument s_doc;
    private static volatile XmlNamespaceManager s_nsmgr;
    private static readonly object s_lock = new object();

    private static void EnsureStaticMembers()
    {
        if (s_doc == null || s_nsmgr == null)
        {
            lock (s_lock)
            {
                if (s_doc == null || s_nsmgr == null)
                {
                    // The following method might fail
                    // with an exception, but if it succeeds,
                    // s_doc and s_nsmgr will be initialized
                    s_doc = LoadDoc(out s_nsmgr);
                }
            }
        }
    }

    public XmlNamespaceManager NamespaceManager
    {
        get
        {
            EnsureStaticMembers();
            return s_nsmgr;
        }
    }

    public XmlDocument GetDocClone()
    {
        EnsureStaticMembers();
        return (XmlDocument)s_doc.Clone();
    }
}
4

1 回答 1

2

如果您使用.NET 4.0,您可以参考Lazy<T>LazyThreadSafetyMode(这取决于您是否希望在多线程环境中创建 T 的少数实例。在您的情况下,您需要参考Lazy<T>(Func<T> func, LazyThreadSafetyMode)构造函数 -这里(MSDN)

否则(如果您使用 3.5 或更低版本),您可以使用 CAS 技术创建单个实例而无需锁定。

像这样的东西:

get {
    if( _instance == null) {
        var singleton = new Singleton();
        if(Interlocked.CompareExchange(ref _instance, singleton, null) != null) {
            if (singleton is IDisposable) singleton.Dispose();
        }
    }
    return _instance;
}

但是,在这里您只能实现 LazyThreadSafetyMode.Publications 行为 - 只有一个实例对其他线程可见,但很少可以创建。

此外,在代码中仔细检查 null 不应该有任何问题 - 它在 .NET 世界中是安全的(至少在 x86 机器和相关的内存模型上)。在 2004 年之前,Java 世界存在一些问题,AFAIK。

于 2010-08-09T09:04:15.520 回答