我有一个对象Product
,它存储在我的应用程序的本地缓存中。使用一些ORM代码从数据库加载此产品缓存,我无法轻易更改。为简单起见,Product
为:
Public Class Product
Public Property ID as Integer
Public Property Name as String
Public Property Price as Decimal
Public Property Rank as Integer
End Class
产品存储在本地缓存中:
Public Class ProductList
Public Shared Function GetCache as List(Of Product)
Static _List as List(Of Product)
If _List is Nothing then
'Code to load Data and populate List from DB
End If
Return _List
End Function
End Class
这是大大简化的,但你明白了。
Rank
属性是基于过去90天内所有销售额的未绑定计算字段,因此常见产品在搜索中显得更高。我想在后台线程上生成排名 - 因为它可能很耗时,并且不时刷新它。像这样:
Public Sub UpdateRank
Dim dt as Datatable
dt = GetDataTable("exec usp_GetProductRank") 'Returns [ID, Rank]
For each row in dt.rows
_prod = getCache.getbyID(row.item(0))
If _prod isnot Nothing then
_prod.rank = row.item(1)
End If
Next
End Sub
在更新排名时可能会使用缓存,从而导致脏读,但我很高兴接受这一点。我想要做的是以线程安全的方式执行此操作。也就是说,更新集合而不必担心是否添加和删除了某些内容等。
我可以使用System.ComponentModel.BackgroundWorker
执行此更新吗?我在主UI中使用了大量的线程来处理这类事情,但这是DLL中的非UI类。我在考虑先将缓存拉入Dictionary(of Integer, Product)
吗?
处理此问题的最佳方法是什么?
答案 0 :(得分:1)
当您使用对象的共享写访问时,您需要使用锁或信号量来避免冲突。执行此操作时,它将告诉其他线程等待对象解锁。这不需要cpu资源。当对象被解锁时,下一个线程可以先到先得的方式访问它(理论上)。
F.ex:
VB.Net:
Class ThreadSafe
Private Shared _locker As Object = New Object
Private Shared Sub Go()
SyncLock _locker
If (_val2 <> 0) Then
Console.WriteLine((_val1 / _val2))
End If
_val2 = 0
End SyncLock
End Sub
End Class
C#:
class ThreadSafe
{
static readonly object _locker = new object();
static int _val1, _val2;
static void Go()
{
lock (_locker)
{
if (_val2 != 0) Console.WriteLine (_val1 / _val2);
_val2 = 0;
}
}
}
示例来自免费电子书,它是多线程的绝佳参考: http://www.albahari.com/threading/part2.aspx#_Locking