我需要根据一组有限的字符串在一个区域中做一个关键部分。我希望共享同一字符串实例的锁(有点类似于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>?
HashSet<string>
例如,创建一个Dictionary<string, object>为每个字符串实例创建一个新的锁对象的更好吗?
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())) { ... } } }
不鼓励锁定字符串,主要原因是(由于字符串绑定)某些其他代码可能会在您不知道的情况下锁定相同的字符串实例。可能导致死锁情况。
现在,在大多数具体情况下,这可能是一个牵强附会的方案。这是图书馆的一般规则。
但是,另一方面,字符串的好处是什么呢?
因此,一点一点:
这种方法有什么问题吗?
是的,但主要是理论上的。
以这种方式锁定字符串对象是否可以,并且在使用HashSet时是否存在线程安全问题?
在HashSet<>只要线程唯一同时读取不参与线程安全的。
HashSet<>
例如,创建一个为每个字符串实例创建一个新的锁定对象的Dictionary更好吗?
是。只是为了安全起见。在大型系统中,避免死锁的主要目的是将锁对象尽可能地保持本地和私有。只有有限数量的代码才能访问它们。