昨天我发现我们使用的一个简单缓存对象存在多线程问题:
If Dictionary.Contains(lsKey.ToLower) Then 'if rate cached, then return value
lvResult = Dictionary.Item(lsKey.ToLower)
Else 'else retrieve from database, store, and return value
lvResult = GetRateFromDB(voADO,
veRateType,
vdEffDate)
Dictionary.Add(lsKey.ToLower, lvResult)
End If
我们在我们的 asp.net 网站上发现了这个问题。消息中的错误信息类似于“您试图向已经存在的哈希表添加值。从上面的代码中可以看出,这种情况发生的可能性肯定会退出。我对等待句柄有些熟悉,并认为它们会解决问题. 所以我在班级级别声明了我的等待句柄:
private Shared _waitHandle as new AutoResetEvent(True)
然后在有问题的特定代码部分:
_waitHandle.Wait()
If Dictionary.Contains(lsKey.ToLower) Then 'if rate cached, then return value
lvResult = Dictionary.Item(lsKey.ToLower)
Else 'else retrieve from database, store, and return value
lvResult = GetRateFromDB(voADO,
veRateType,
vdEffDate)
Dictionary.Add(lsKey.ToLower, lvResult)
End If
_waitHandle.Set()
由于某种原因,上面的以下代码总是被阻止。即使是第一个线程也访问了代码。我玩了一段时间,甚至尝试在构造函数中将等待句柄设置为发出信号,但我永远无法让它工作。
我最终改用以下方法,效果很好:
SyncLock loLock
If Dictionary.Contains(lsKey.ToLower) Then 'if rate cached, then return value
lvResult = Dictionary.Item(lsKey.ToLower)
Else 'else retrieve from database, store, and return value
lvResult = GetRateFromDB(voADO,
veRateType,
vdEffDate)
Dictionary.Add(lsKey.ToLower, lvResult)
End If
End SyncLock
所以我有两个问题:
- 为什么等待句柄解决方案不起作用?
- SynLock 是在这种情况下使用的正确/优化的锁类型吗?