首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >与syncRoot相比,锁定集合有什么缺点吗?

与syncRoot相比,锁定集合有什么缺点吗?
EN

Stack Overflow用户
提问于 2010-10-12 07:22:22
回答 4查看 5.8K关注 0票数 4

我想知道锁定一个集合(如List<T>HashSet<T>Dictionary<TKey, TValue> )而不是简单的object是否有任何缺点。

注意:在下面的示例中,这是发生锁的唯一位置,它不是从多个位置锁定的,但静态方法可以从多个线程调用。此外,永远不会在GetSomething方法之外访问_dict

我当前的代码如下所示:

代码语言:javascript
复制
private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
public static string GetSomething(string key)
{
    string result;
    if (!_dict.TryGetValue(key, out result))
    {
        lock (_dict)
        {
            if (!_dict.TryGetValue(key, out result))
            {
                _dict[key] = result = CalculateSomethingExpensive(key);
            }
        }
    }
    return result;
}

另一位开发人员告诉我,锁定集合会导致问题,但我对此持怀疑态度。如果我这样做,我的代码会更有效率吗?

代码语言:javascript
复制
private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
private static readonly object _syncRoot = new object();
public static string GetSomething(string key)
{
    string result;
    if (!_dict.TryGetValue(key, out result))
    {
        lock (_syncRoot)
        {
            if (!_dict.TryGetValue(key, out result))
            {
                _dict[key] = result = CalculateSomethingExpensive(key);
            }
        }
    }
    return result;
}
EN

回答 4

Stack Overflow用户

发布于 2010-10-12 07:41:58

在本例中,我将锁定集合;锁定的目的直接与集合相关,而不是与任何其他对象相关,因此将其用作锁定对象具有一定程度的自注解。

不过,我还是会做一些改变。

我在文档中找不到TryGetValue是线程安全的,如果您在字典处于无效状态时调用它,它不会抛出异常(或者更糟),因为它已经添加了一半的新值。因为它不是原子的,所以这里使用的双重读取模式(为了避免获取锁所花费的时间)是不安全的。必须将其更改为:

代码语言:javascript
复制
private static readonly Dictionary<string, string> _dict = new Dictionary<string, string>();
public static string GetSomething(string key)
{
    string result;
    lock (_dict)
    {
        if (!_dict.TryGetValue(key, out result))
        {
            _dict[key] = result = CalculateSomethingExpensive(key);
        }
    }
    return result;
}

如果成功的读取可能多于不成功的读取(因此需要写入),则使用ReaderWriterLockSlim将在这些读取上提供更好的并发性。

编辑:我只是注意到你的问题不是关于偏好的,而是关于效率的。实际上,在整个系统中多使用4字节内存(因为它是静态的)的效率差异绝对为零。这个决定根本不是关于效率的,而是因为两者具有同等的技术价值(在本例中)是关于您发现锁定集合还是锁定单独的对象更能更好地向其他开发人员(包括将来的您)表达您的意图。

票数 6
EN

Stack Overflow用户

发布于 2010-10-12 07:28:26

不是的。只要变量不能从其他任何地方访问,并且您可以保证只在这里使用锁,就不会有任何负面影响。事实上,Monitor.Enter (这是C#中的lock所使用的)的文档正是这样做的。

但是,作为一般规则,我仍然建议使用私有对象进行锁定。一般来说,这样做更安全,而且如果您将此对象暴露给任何其他代码,也会保护您,因为您不会打开您的对象被其他代码锁定的可能性。

票数 3
EN

Stack Overflow用户

发布于 2010-10-12 07:29:15

直接回答你的问题:no

无论您锁定的是什么对象,都没有区别。.NET只关心它的引用,它的工作原理就像一个指针。考虑一下将.NET锁定为一个大型的同步哈希表,其中的键是对象引用,值是一个布尔值,表示您可以进入监视器或不进入监视器。如果两个线程锁定到不同的对象(a != b),它们可以同时进入锁的监视器,即使a.Equals(b) (这非常重要!)。但是如果他们锁定了a和b,并且(a==b),一次只有一个会出现在监视器中。

只要dict没有在您的作用域之外被访问,您就不会对性能产生影响。如果dict在其他地方可见,其他用户代码可能会锁定它,即使不是必须的(假设你的同桌是个笨蛋,并锁定到他在代码中找到的第一个随机对象)。

希望能对您有所帮助。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3910628

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档