1

我正在使用静态成员来缓存一些数据,并且我相信在首次填充缓存数据时我遇到了某种并发问题。这个问题是零星的,似乎跟app pool的回收有关(虽然很多时候不会有问题)。

最初我的 _CachedData 成员为空。当调用 FindAll() 方法时,它将在 _CachedData 不为空时使用缓存的数据,否则它将从数据库中加载数据。每当对数据执行插入、更新或删除操作时,_CachedData 成员都会设置为 null,尽管在应用程序池回收后首次加载应用程序时绝不应该发生这种情况。

当我将 TestClass 对象添加到 _CachedData 的结果时,我得到的错误是对象引用错误。我只是不明白这是怎么可能的,因为我在进入 for each 循环之前对 _CachedData 执行了空检查。

Public Class TestClass

    Private Shared _CachedData As Collection(Of TestClass) = Nothing

    Sub New()

    End Sub

    Public Shared Function FindAll() As Collection(Of Content.TestClass)
        Dim result As New Collection(Of TestClass)()

        If _CachedData IsNot Nothing Then
            ' retrieve from cache
            For Each tc As TestClass In _CachedData
                result.Add(CType(tc.MemberwiseClone(), TestClass))
            Next
        Else
            result = GetFromDatabase()

            ' save to cache
            _CachedData = New Collection(Of TestClass)()
            SyncLock _CachedData
                ' make sure the cache wasn't populated while we were aquiring the lock
                If _CachedData.Count = 0 Then
                    For Each tc As TestClass In result
                        _CachedData.Add(CType(tc.MemberwiseClone(), TestClass))
                    Next
                End If
            End SyncLock
        End If

        Return result
    End Function

法夫

4

1 回答 1

0

对于初学者,您实际上不应该锁定对象本身,因为您将对该对象进行更改。您应该这样更新您的代码:

Private Shared _CachedData As Collection(Of TestClass) = Nothing
Private Shared ReadOnly _CachedDataLock As Object = New Object()

Public Shared Function FindAll() As Collection(Of Content.TestClass)
    Dim result As New Collection(Of TestClass)()

    If _CachedData IsNot Nothing Then
        ' retrieve from cache, using a local instance to avoid race-conditions
        Dim localCachedData As Collection(Of TestClass) = _CachedData
        For Each tc As TestClass In localCachedData 
            result.Add(CType(tc.MemberwiseClone(), TestClass))
        Next
    Else
        result = GetFromDatabase()

        ' save to cache
        SyncLock _CachedDataLock
            ' make sure the cache wasn't populated while we were aquiring the lock
            If _CachedData Is Nothing Then
                _CachedData = New Collection(Of TestClass)()
                For Each tc As TestClass In result
                    _CachedData.Add(CType(tc.MemberwiseClone(), TestClass))
                Next
            End If
        End SyncLock
    End If

    Return result
End Function
于 2013-02-28T17:42:58.127 回答