[英]Lock needed on singleton lookup table?
我下面有一个单身人士。 我有多个线程使用查找来检查值是否有效。 自从我用共享内存完成任务以来已经有一段时间了,所以我想确保哪些锁是必要的。 我不确定我是否需要并发集而不是HashSet,因为我只插入一次值。
我在Instance属性上有[MethodImpl(MethodImplOptions.Synchronized)]
,因为我读到属性没有sycrhonized(有意义)。 这应该可以防止创建多个实例,虽然我不确定我是否真的应该担心这个问题(只需要重新加载集合的额外成本?)。
我应该使FipsIsValid
函数Syncrhonized,还是使用某种并发集? 或者既不必要?
public class FipsLookup
{
private static FipsLookup instance;
private HashSet<string> fips;
private FipsLookup()
{
using (HarMoneyDB db = new HarMoneyDB())
{
instance.fips = new HashSet<string>(db.Counties.Select(c => c.FIPS).ToArray());
}
}
[MethodImpl(MethodImplOptions.Synchronized)]
public static FipsLookup Instance
{
get
{
if (instance == null)
{
instance = new FipsLookup();
}
return instance;
}
}
public static bool FipsIsValid(string fips)
{
var instance = FipsLookup.Instance;
return instance.fips.Contains(fips);
}
}
我应该使FipsIsValid函数Syncrhonized,还是使用某种并发集? 或者既不必要?
我认为这个答案的关键是你只在HashSet
上执行查找,而不是改变它。 由于它只被初始化一次,并且只有一次,因此不需要同步查找。
如果你确定在确实需要改变它的方式,那么就需要使用正确的lock
或并发集合。
在旁注中,您可以通过在静态构造函数中初始化实例字段来简化单例:
private static FipsLookup instance;
static FipsLookup()
{
instance = new FipsLookup();
}
现在您可以使Instance
返回该字段,而无需使用[MethodImpl(MethodImplOptions.Synchronized)]
:
public static FipsLookup Instance
{
get
{
return instance;
}
}
这是安全的,因为Instance
是同步的,相当于一个锁。 所有写入都发生在该锁定之下。 释放锁会刷新所有写入(释放屏障)。
此外,所有读取首先通过锁定。 无法观察到部分编写的hashset。 此答案的先前版本提出以下不正确的声明:
这不是严格安全的(在ECMA下),因为读者可能会看到半写的
HashSet
。 在实践中它是安全的(在Microsoft CLR,因为所有商店都是发布)但我不会使用它,因为没有理由。
写这篇文章的时候,我没注意到MethodImplOptions.Synchronized
。 因此,为了您的娱乐,这就是您忘记锁定时会发生的事情。
可能你应该使用Lazy<T>
为你处理这个,它给你无锁读取。
静态成员上的MethodImplOptions.Synchronized
有点邪恶,因为它锁定了类的类型对象。 让我们希望没有其他人锁定这个(共享)对象。 我会在代码审查中失败,主要是因为没有理由引入这种代码味道。
HashSet类不是线程安全的,并且没有保证你可以从多个线程访问它,一切都会好的。 我更喜欢使用ConcurrentDictionary。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.