[英]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.