我应该总是锁定静态方法吗?

时间:2011-11-03 06:36:45

标签: vb.net static locking thread-safety shared

在以下示例中, GetList 返回静态(共享)变量的实例。那个人需要锁定以保证线程安全。

但是 DoSomething 呢?它不使用方法之外的任何静态变量?它也需要锁定吗?

编辑:我想澄清一下,在这种特殊情况下,我希望DoSomething始终按顺序打印0-100(即没有0​​123745 ...),无论调用线程数是多少。或者,通常,不同的线程不会影响彼此的变量(打印到控制台只是一个例子)。以下示例中的语言是VB.NET。

正如paxdiablo所说:

  

在这种情况下,似乎唯一触及的是局部变量   我,每个函数调用都有一个单独的副本。   换句话说,它不需要保护。

这正是我试图解决的问题。谢谢!

Public Class TestClass

    Private Shared lock As New Object
    Private Shared list As List(Of Integer)

    Public Shared Function GetList() As List(Of Integer)

        SyncLock lock
            If list Is Nothing Then
                list = New List(Of Integer)
            End If
            Return list
        End SyncLock

    End Function

    Public Shared Sub DoSomething()

        Dim i As Integer

        For i = 0 To 100
            Console.WriteLine(i.ToString)
        Next

    End Sub

End Class

3 个答案:

答案 0 :(得分:1)

那么,这主要取决于你没有指定的语言,但一般来说,如果代码没有触及另一个线程也可以触及的资源,它就不必受到​​保护。

在这种情况下,似乎唯一触及的是局部变量i,它为每个函数调用都有一个单独的副本。换句话说,它不需要保护。

当然,可以说控制台也是一种资源,可能需要保护,例如,如果您不希望线条互相干扰(同步写入)或者希望整个百线输出为单个单位(同步整个for循环)。

但这并不能真正保护控制台,只是这里使用它的代码块。其他线程仍然可以通过不使用此方法写入控制台。

底线,我认为你不需要在第二种方法中使用synclock。


如果您在VB.Net中使用SyncLock,则下面的这一部分无关紧要(现在似乎就是这种情况)。无论您如何离开区块,语言都可以保证锁定被释放。我会把它留给歇斯底里的目的。

我会在第一种方法中关注你的synclock放置,特别是如果return语句是控制权转移回调用者(并且synclock没有自动解锁)范围变更)。这看起来像你可以在没有解锁的情况下返回,这将是一场灾难。我认为以下更合适:

Public Shared Function GetList() As List(Of Integer)
    SyncLock lock
        If list Is Nothing Then
            list = New List(Of Integer)
        End If
    End SyncLock
    Return list
End Function

答案 1 :(得分:0)

一般来说,没有。

您需要明确GetList应用锁定的原因。正如你在第一句中暗示的那样,它并不是因为它返回了一个静态变量。您可以删除锁定代码,GetList仍然是线程安全的。但是,通过锁定,还有一个额外的保证 - 列表只会创建一次,并且此代码的​​所有调用者都将收到对同一列表的引用。

答案 2 :(得分:0)

为什么不完全避免锁定而只是这样做:

Public Class TestClass

    Private Shared lock As New Object
    Private Shared list As New List(Of Integer)

    Public Shared Function GetList() As List(Of Integer)
        Return list
    End Function

    Public Shared Sub DoSomething()
        Dim i As Integer
        For i = 0 To 100
            Console.WriteLine(i.ToString)
        Next
    End Sub

End Class