静态属性和锁定用法

时间:2009-03-27 20:31:01

标签: .net vb.net performance multithreading locking

此代码是否正确或是否有任何随机线程死锁等可能性?

使用静态属性并锁定在一起是否是一个好主意?或者是静态属性线程安全吗?

Private Shared _CompiledRegExes As List(Of Regex)
Private Shared Regexes() As String = {"test1.Regex", "test2.Regex"}
Private Shared RegExSetupLock As New Object

Private Shared ReadOnly Property CompiledRegExes() As List(Of Regex)
    Get
        If _CompiledRegExes Is Nothing Then
        SyncLock RegExSetupLock

            If _CompiledRegExes Is Nothing Then
                _CompiledRegExes = New List(Of Regex)(Regexes.Length - 1)

                For Each exp As String In Parser.Regexes
                    _CompiledRegExes.Add(New Regex(exp, RegexOptions.Compiled Or RegexOptions.CultureInvariant Or RegexOptions.IgnoreCase))
                Next

            End If

        End SyncLock

    End If

    Return _CompiledRegExes

End Get
End Property

如果不是明显的代码正在编译正则表达式并存储在List(Of Regex)中,那么它们可以更快地运行。并且它是共享的,因此每个类的实例都可以从中获益。

6 个答案:

答案 0 :(得分:8)

您的代码不是线程安全的,因为您使用的是双重检查锁定,而不会使字段变为volatile。不幸的是VB.NET没有volatile修饰符,所以你不能应用正常的修复。只需每次获取锁,或者在初始化类型时使用静态初始化来初始化_CompiledRegExes。

有关单身人士的详细讨论,请参阅my singleton page - 我知道这不是相当单身人士,但它很接近。该页面提供了C#代码,但它应该很容易理解。

此外,我通常建议将锁变量设置为只读。你真的不想改变价值:)

一般而言:

  • 不,静态属性不是自动线程安全的
  • 是的,可以锁定静态变量(但显式初始化,就像你正在做的那样)
  • 除非真的知道你在做什么,否则不要尝试编写无锁或低锁的代码。我认为自己对线程知之甚少,我仍然不尝试使用双重检查锁定等。
  • 类型初始化是线程安全的(如果你有复杂的初始化器最终会引用彼此的话,会有一些注意事项)所以这是进行初始化的好时机 - 那么你真的需要一把锁。

编辑:您不需要将类型设为单身。只需编写函数来初始化列表并将其返回,然后在初始化器中为变量使用该函数:

' This has to be declared *before* _CompiledRegExes '
' as the initializer will execute in textual order '
' Alternatively, just create the array inside BuildRegExes '
' and don't have it as a field at all. Unless you need the array '
' elsewhere, that would be a better idea. '
Private Shared ReadOnly Regexes() As String = {"test1.Regex", "test2.Regex"}

Private Shared ReadOnly _CompiledRegExes As List(Of Regex) = BuildRegExes()

Private Shared ReadOnly Property CompiledRegExes() As List(Of Regex)
    Get
        Return _CompiledRegExes
    End Get
End Property

Private Shared Function BuildRegExes() As List(Of Regex)
    Dim list = New List(Of Regex)(Regexes.Length - 1)

    For Each exp As String In Regexes
        _CompiledRegExes.Add(New Regex(exp, RegexOptions.Compiled Or RegexOptions.CultureInvariant Or RegexOptions.IgnoreCase))
    Next
    Return list
End Function

答案 1 :(得分:2)

(由jonskeet编辑)这篇文章只是为了让课程开始的格式化。如果在代码之前没有文本,不知道它为什么会失败。)

Class Better
    Private Shared Regexes() As String = {"test1.Regex", "test2.Regex"}
    Private Shared _CompiledRegExes As List(Of Regex) = BuildList(Regexes)

    Private Shared Function BuildList(ByVal source() As String) As List(Of Regex)
        Dim result = New List(Of Regex)(Regexes.Length - 1)
        For Each exp As String In source
            result.Add(New Regex(exp, RegexOptions.Compiled Or RegexOptions.CultureInvariant Or RegexOptions.IgnoreCase))
        Next
        Return result
    End Function
    Public Shared ReadOnly Property _CompiledRegExes1() As List(Of Regex)
        Get
            Return _CompiledRegExes
        End Get
    End Property

End Class

Class MoreBetter
    Private Shared ReadOnly Regexes() As String
    Private Shared ReadOnly _CompiledRegExes As List(Of Regex)

    Shared Sub New()
        Regexes = New String() {"test1.Regex", "test2.Regex"}
        _CompiledRegExes = New List(Of Regex)(Regexes.Length - 1)
        For Each exp As String In Regexes
            _CompiledRegExes.Add(New Regex(exp, RegexOptions.Compiled Or RegexOptions.CultureInvariant Or RegexOptions.IgnoreCase))
        Next
    End Sub

    Public Shared ReadOnly Property _CompiledRegExes1() As List(Of Regex)
        Get
            Return _CompiledRegExes
        End Get
    End Property

End Class

编辑:我喜欢第二个的原因是它不容易出错。如果在“Private Shared Regexes()”

之前意外移动了“Private Shared _CompiledRegExes”,则第一个将无效

答案 2 :(得分:1)

VB.Net有一个Static关键字,可用于在成员或属性中声明变量。以这种方式声明的变量在调用方法时保持其状态,并保证是线程安全的(在幕后使用Monitor类实现)。

答案 3 :(得分:1)

虽然我很少支持使用这种方法,但它是合法的。

Class UsingStatic
Private Shared Regexes() As String = {"test1.Regex", "test2.Regex"}
Public Shared ReadOnly Property CompiledRegExes() As List(Of Regex)
    Get
        Static _CompiledRegExes As List(Of Regex) = BuildList(Regexes) <--executes once
        Return _CompiledRegExes <-- executes every time it is called
    End Get
End Property

Private Shared Function BuildList(ByVal source() As String) As List(Of Regex)
    Dim result = New List(Of Regex)(Regexes.Length - 1)
    For Each exp As String In source
        result.Add(New Regex(exp, RegexOptions.Compiled Or RegexOptions.CultureInvariant Or RegexOptions.IgnoreCase))
    Next
    Return result
End Function

End Class

请注意,您必须将_CompiledRegExes的构造函数放在同一行上。这个微小的变化会让你每次都得到一个新的物体。

Public Shared ReadOnly Property CompiledRegExes() As List(Of Regex)
    Get
        Static _CompiledRegExes As List(Of Regex) <--executes once
        _CompiledRegExes = BuildList(Regexes) <-- executes every time it is called
        Return _CompiledRegExes
    End Get
End Property

答案 4 :(得分:0)

当您只有一个资源时,不会发生死锁。

关于静态属性,它们不是自动线程安全的。这是锁定私有静态字段的常用方法。

答案 5 :(得分:0)

来自msdn的

“lockobject表达式应始终评估为专属于您的类的对象。您应该声明一个Private对象变量来保护属于当前实例的数据,或者声明一个Private Shared对象变量来保护所有公共数据实例“。