Hashtable.Synchronized是否适合在多线程环境中用作简单缓存?

时间:2012-09-23 18:03:20

标签: .net collections hashtable

我目前正在使用Hashtable包装为Hashtable.Synchronized作为可以由多线程环境(例如asp.net)使用的库中的简单缓存 - 这是否适用于此采集?我知道.Net 4.0中有更合适的构造,但我仍然坚持使用.Net 3.5。

如果它有任何区别,这个缓存会被频繁读取,并且很少被写入(但需要保持线程安全)。

基本用法类似于:

Private Shared ReadOnly ExpressionCache As Hashtable = Hashtable.Synchronized(New Hashtable())

..snip...

If Not ExpressionCache.ContainsKey(myKey) Then
      ExpressionCache(myKey) = myExpensiveOperationToInit()
End If
Return  ExpressionCache(myKey)

..snip..

我在这里做了一些有潜在危险的事情,或者这是一个可接受的用例?

1 个答案:

答案 0 :(得分:4)

实际上,Hashtable(与Dictionary<,>不同)已经具有非常好的线程语义用作缓存:它对读者来说是线程安全的(但需要锁定作者) - from MSDN

  

Hashtable是线程安全的,可供多个读取器线程和单个写入线程使用。当只有一个线程执行写(更新)操作时,它对多线程使用是线程安全的,如果编写器被序列化为Hashtable,则允许无锁读取。

(它还提到.Synchronized支持多个作家,但坦率地自己控制这个通常会给出更好的结果)

但是,为避免幻像读取,您不应使用单独的“包含”/“获取”操作;标准用途可能是(例如使用C#):

public YourType Get(string key) {
    return (YourType) expressionCache[key];
}
public void Set(string key, YourType value) {
    lock(expressionCache) {
        expressionCache[key] = value;
    }
}

关键点:

  • 只有“set”有任何锁定
  • “get”中只有一个操作
  • 在集合中使用索引器,而不是Add(那么您不需要先检查“包含”)

在大多数常见的线程场景中,.Synchronized包装器的价值实际上非常小。