在执行块之前获取语句块的独占锁。
语法
SyncLock lockobject
[ block ]
End SyncLock
部件
lockobject
必填。 计算结果为对象引用的表达式。
block
可选。 获取锁时要执行的语句块。
End SyncLock
终止块 SyncLock
。
注解
该 SyncLock
语句可确保多个线程不会同时执行语句块。
SyncLock
防止每个线程进入块,直到没有其他线程执行它。
最常见的用途 SyncLock
是防止数据同时由多个线程更新。 如果作数据的语句必须进入完成状态且不会中断,请将这些语句放入块中 SyncLock
。
受排他锁保护的语句块有时称为 关键节。
规则
分支。 不能从块外部分支到
SyncLock
块。锁定对象值。 值
lockobject
不能Nothing
为 . 在语句中使用SyncLock
锁对象之前,必须创建锁对象。在执行块时
SyncLock
,无法更改其值lockobject
。 该机制要求锁对象保持不变。不能在块中使用
SyncLock
Await 运算符。
行为
机制。 当线程到达
SyncLock
语句时,它会计算lockobject
表达式并挂起执行,直到它获取表达式返回的对象上的排他锁。 当另一个线程到达语句时SyncLock
,它不会获取锁,直到第一个线程执行End SyncLock
该语句。受保护的数据。 如果
lockobject
为Shared
变量,排他锁可防止类的任何实例中的线程在执行块时执行SyncLock
该块。 这会保护在所有实例之间共享的数据。如果
lockobject
实例变量(不是Shared
),则锁会阻止当前实例中运行的线程与同一实例中的另一个线程同时执行SyncLock
该块。 这会保护单个实例维护的数据。获取和发布。
SyncLock
块的行为类似于Try...Finally
块获取Try
独占锁lockobject
的构造,块Finally
释放它。 因此,SyncLock
无论如何退出块,块都保证释放锁。 即使在未经处理的异常的情况下也是如此。框架调用。 该
SyncLock
块通过调用Enter
命名空间中的System.Threading类和Exit
方法Monitor
来获取和释放排他锁。
编程实践
表达式 lockobject
应始终计算为属于类的对象。 应声明一个 Private
对象变量来保护属于当前实例的数据,或者声明一个 Private Shared
对象变量来保护所有实例通用的数据。
不应使用 Me
关键字为实例数据提供锁定对象。 如果类外部的代码具有对类实例的引用,则它可以将该引用用作完全不同于你的块的锁对象 SyncLock
,从而保护不同的数据。 这样,你的类和其他类就可以互相阻止执行其无关 SyncLock
的块。 同样,对字符串的锁定可能会有问题,因为使用同一字符串的进程中的任何其他代码将共享同一锁。
不应使用 Me.GetType
该方法为共享数据提供锁定对象。 这是因为 GetType
始终返回给定类名的相同 Type
对象。 外部代码可以调用 GetType
类并获取所使用的同一锁对象。 这将导致两个类相互阻止其 SyncLock
块。
例子
DESCRIPTION
下面的示例演示了一个维护简单消息列表的类。 它在数组中保存消息,以及变量中该数组的最后一个已用元素。 该过程 addAnotherMessage
递增最后一个元素并存储新消息。 这两个作受 SyncLock
语句和 End SyncLock
语句的保护,因为一旦最后一个元素递增,必须先存储新消息,然后任何其他线程才能再次递增最后一个元素。
simpleMessageList
如果类在其所有实例之间共享了一个消息列表,则变量messagesList
将被messagesLast
声明为 Shared
。 在这种情况下, messagesLock
变量也应是 Shared
,以便每个实例使用一个锁对象。
Code
Class simpleMessageList
Public messagesList() As String = New String(50) {}
Public messagesLast As Integer = -1
Private messagesLock As New Object
Public Sub addAnotherMessage(ByVal newMessage As String)
SyncLock messagesLock
messagesLast += 1
If messagesLast < messagesList.Length Then
messagesList(messagesLast) = newMessage
End If
End SyncLock
End Sub
End Class
DESCRIPTION
以下示例使用线程和 SyncLock
。 只要 SyncLock
存在该语句,语句块就是关键节, balance
并且永远不会成为负数。 可以注释掉 SyncLock
和 End SyncLock
语句以查看退出 SyncLock
关键字的效果。
Code
Imports System.Threading
Module Module1
Class Account
Dim thisLock As New Object
Dim balance As Integer
Dim r As New Random()
Public Sub New(ByVal initial As Integer)
balance = initial
End Sub
Public Function Withdraw(ByVal amount As Integer) As Integer
' This condition will never be true unless the SyncLock statement
' is commented out:
If balance < 0 Then
Throw New Exception("Negative Balance")
End If
' Comment out the SyncLock and End SyncLock lines to see
' the effect of leaving out the SyncLock keyword.
SyncLock thisLock
If balance >= amount Then
Console.WriteLine("Balance before Withdrawal : " & balance)
Console.WriteLine("Amount to Withdraw : -" & amount)
balance = balance - amount
Console.WriteLine("Balance after Withdrawal : " & balance)
Return amount
Else
' Transaction rejected.
Return 0
End If
End SyncLock
End Function
Public Sub DoTransactions()
For i As Integer = 0 To 99
Withdraw(r.Next(1, 100))
Next
End Sub
End Class
Sub Main()
Dim threads(10) As Thread
Dim acc As New Account(1000)
For i As Integer = 0 To 9
Dim t As New Thread(New ThreadStart(AddressOf acc.DoTransactions))
threads(i) = t
Next
For i As Integer = 0 To 9
threads(i).Start()
Next
End Sub
End Module