8

我想知道哪种方法以线程安全的方式加载数据更好。传统上,我使用了双锁模式,这很好地达到了目的。现在,随着 System.Lazy 类型的添加,我想知道依赖 Lazy 和 Loading 的内部结构是否更好,并以更好的方式完成工作。它看起来确实更干净,更容易阅读,但它更好吗?

有什么想法吗?

namespace SomeNameSpace
{
  public class DataStoreContext
  {
    private readonly static Lazy<DataStoreContext> context = new Lazy<DataStoreContext>(() => new DataStoreContext());
    private Lazy<Dictionary<string, Entity>> _entities = new Lazy<Dictionary<string, Entity>>(() => { return DataStoreContext.Instance.Load(); });
    private readonly object _syncRoot = new object();
    private DataStoreContext()
    {
    }

    public Dictionary<string, Entity> Data
    {
      get { return _entities.Value; }
    }

    public static DataStoreContext Instance
    {
      get { return context.Value; }
    }

    private Dictionary<string, Entity> Load()
    {
      // Load Data from some data store. 
      return null;
    }

    private Dictionary<string, Entity> LoadWithLock()
    {
      if (_entities == null)
      {
        lock (_syncRoot)
        {
          if (_entities == null)
          {
            Dictionary<string, Entity> entities = this.Load();
            _entities = entities;
            return _entities;
          }
        }
      }

      return _entities ;
    }

    public void Clear()
    {

     _entities = new Lazy<Dictionary<string, Entity>>(() => { return DataStoreContext.Instance.Load(); });

    }
  }
}
4

2 回答 2

8

它看起来确实更干净,更容易阅读,但它更好吗?

是的。双重检查锁定很难做到正确。它需要一个内存屏障才能正确。CIL* 实际上并不能保证您的实施是安全的。

有关详细信息,请参阅此 Wikipedia 条目

通过使用Lazy<T>,您获得的代码不仅更干净,而且在所有平台上实际上都是正确的。

*请注意,由于平台的内存模型,这可能在运行 Microsoft 运行时的 x86 和 x64 上完美运行。但是,如果没有适当的内存屏障,规范不能保证它是正确的。

于 2012-10-10T01:08:42.373 回答
3

根据 MSDN 的文档:

默认情况下,Lazy 类的所有公共和受保护成员都是线程安全的,并且可以从多个线程同时使用。这些线程安全保证可以通过类型构造函数的参数可选地和每个实例删除。

对于读写操作来说,它是相当线程安全的。因此,我会说坚持这个,因为它更干净。

但是,正如文档所述,您可以使用构造函数的一些可选参数来关闭该线程安全性。

于 2012-10-10T01:07:49.707 回答