1

我目前正在使用包装为 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..

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

4

1 回答 1

4

实际上,Hashtable(不像Dictionary<,>)已经具有非常好的线程语义,可用作缓存:它对读取器是线程安全的(但需要对写入器进行锁定) -来自 MSDN

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

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

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

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

关键点:

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

在最常见的线程场景中,.Synchronized包装器实际上几乎没有价值。

于 2012-09-23T18:40:59.800 回答