一尘不染

可以将字符串用作锁定对象吗?

c#

我需要根据一组有限的字符串在一个区域中做一个关键部分。我希望共享同一字符串实例的锁(有点类似于String.Intern方法)。

我正在考虑以下实施:

public class Foo
{
    private readonly string _s;
    private static readonly HashSet<string> _locks = new HashSet<string>();

    public Foo(string s)
    {
        _s = s;
        _locks.Add(s);
    }

    public void LockMethod()
    {
        lock(_locks.Single(l => l == _s))
        {
            ...
        }
    }
}

这种方法有什么问题吗?以这种方式锁定字符串对象是否可以,使用时是否存在线程安全问题HashSet<string>

例如,创建一个Dictionary<string, object>为每个字符串实例创建一个新的锁对象的更好吗?


最终实施

根据建议,我进行了以下实现:

public class Foo
{
    private readonly string _s;
    private static readonly ConcurrentDictionary<string, object> _locks = new ConcurrentDictionary<string, object>();

    public Foo(string s)
    {
        _s = s;
    }

    public void LockMethod()
    {
        lock(_locks.GetOrAdd(_s, _ => new object()))
        {
            ...
        }
    }
}

阅读 648

收藏
2020-05-19

共1个答案

一尘不染

不鼓励锁定字符串,主要原因是(由于字符串绑定)某些其他代码可能会在您不知道的情况下锁定相同的字符串实例。可能导致死锁情况。

现在,在大多数具体情况下,这可能是一个牵强附会的方案。这是图书馆的一般规则。

但是,另一方面,字符串的好处是什么呢?

因此,一点一点:

这种方法有什么问题吗?

是的,但主要是理论上的。

以这种方式锁定字符串对象是否可以,并且在使用HashSet时是否存在线程安全问题?

HashSet<>只要线程唯一同时读取不参与线程安全的。

例如,创建一个为每个字符串实例创建一个新的锁定对象的Dictionary更好吗?

是。只是为了安全起见。在大型系统中,避免死锁的主要目的是将锁对象尽可能地保持本地和私有。只有有限数量的代码才能访问它们。

2020-05-19