1

一部のデータをキャッシュするために静的メンバーを使用していますが、キャッシュされたデータが最初に取り込まれるときに、何らかの同時実行の問題が発生していると思います。この問題は散発的であり、アプリ プールのリサイクルに続くようです (多くの場合、問題はありません)。

最初、_CachedData メンバーは null です。FindAll() メソッドが呼び出されると、_CachedData が null でない場合はキャッシュされたデータが使用され、それ以外の場合はデータベースからデータが読み込まれます。_CachedData メンバーは、データに対して挿入、更新、または削除が実行されるたびに null に設定されますが、これはアプリ プールのリサイクル後にアプリケーションが最初に読み込まれるときに発生することはありません。

私が取得しているエラーは、TestClass オブジェクトを _CachedData の結果として追加しているときに発生するオブジェクト参照エラーです。for each ループに入る前に _CachedData で null チェックを実行しているため、これがどのように可能かわかりません。

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 に答える