假设我有两个线程(Thread1,Thread2),其中线程正在访问给定对象的缓存,例如几乎同时在下面的代码中:
Dim expensiveToGetData = Cache("ExpensiveDataKey")
If ExpensiveToGetData is nothing then
'because the cache has expired
ExpensiveToGetData = LoadExpensiveDataFromDataSource()
Cache("ExpensiveDataKey") = ExpensiveToGetData
end If
ProcessExpensiveData(ExpensiveToGetData)
两个线程都不可能加载缓存,因为它们都从缓存中请求了没有/过期的数据吗?我在本地计算机上运行了一些测试,似乎缓存被加载了不止一次。这是正常模式吗?
答案 0 :(得分:2)
是的,使用该代码肯定有两个不同的请求从Cache中获取Nothing,因此两者都重新加载数据。如果要避免这种情况,则需要同步获取数据的整个操作。
进行同步访问的一种方法是使用类似于:
的代码Dim expensiveToGetData = Cache("ExpensiveDataKey")
If ExpensiveToGetData is nothing then
SyncLock yourLockObject /* YourLockObject should be a Shared object. */
expensiveToGetData = Cache("ExpensiveDataKey")
If expensiveToGetData Is Nothing Then
ExpensiveToGetData = LoadExpensiveDataFromDataSource()
Cache("ExpensiveDataKey") = ExpensiveToGetData
End If
End SyncLock
end If
ProcessExpensiveData(ExpensiveToGetData)
在获取锁之前检查我们是否获得数据的想法是避免在高负载下的环境中过度锁定。如果它不在那里,我们需要在锁内部再次检查,因为在我们获取锁时,另一个线程可能已经获得了数据。
答案 1 :(得分:2)
是的,这是可能的,而且这不是一个理想的模式。作为快速修复,您可以在缓存上建立一个互斥锁作为快速修复,但理想情况下,更好的设计是让缓存充当中间加载昂贵的数据本身。设计模式远不止我所提到的,但它应该让你开始。