vb.net 教程 6-17 使用Monitor类实现线程的同步

如上一节《vb.net 教程 6-16 使用SyncLock语句实现线程的同步 》介绍的SyncLock语句,是一种简单处理同步的方法。

.net还提供了Monitor类处理线程同步。Monitor类比较重要的几个静态方法:

Enter 在指定对象上获取排他锁。 
Exit 释放指定对象上的排他锁。 
TryEnter 尝试获取指定对象上的排他锁,并自动设置一个值,指示是否获取了该锁。 

Monitor的Enter和Exit方法有点类似于SyncLock和End SyncLock。这里重点介绍TryEnter方法。

TryEnter方法的一个重载:

Public Shared Function TryEnter ( _
    obj As Object, _
    millisecondsTimeout As Integer _
) As Boolean

参数:
obj  在其上获取锁的对象。 
millisecondsTimeout 等待锁所需的毫秒数,即在 millisecondsTimeout 毫秒后释放这个锁,不会一直占有,这样其他线程也可以继续下去。
使用Enter或者TryEnter方法时候,锁定的对象所需要满足的条件和SyncLock 的lockobject一样,具体请参看《vb.net 教程 6-16 使用SyncLock语句实现线程的同步

下面将用一个例子说明Monitor类的使用:
使用Monitor类也需要先定义一个模块级变量(只针对本代码):

Private MonitorObj As Object

主代码:

    Sub sample13()
        MonitorObj = New Object
        For i As Integer = 0 To 5
            Dim sample13_Thread As New Thread(AddressOf sample13_doALoop1)
            sample13_Thread.Start(i)
        Next

        Thread.Sleep(100)
        Console.ReadKey()
    End Sub

    Sub sample13_doALoop1(ByVal number As Integer)
        Dim counter As Integer = CType(number, Integer)
        Monitor.TryEnter(MonitorObj, 100)
        For i As Integer = 1 To 100
            Console.Write(" " & counter)
        Next
        Monitor.Exit(MonitorObj)
    End Sub

OK,运行,开始输出。

然后,大概率会出错:

vb.net 教程 6-17 使用Monitor类实现线程的同步

 Monitor 引发 了SynchronizationLockException错误,并显示消息“从不同步的代码块中调用了对象同步方法”。
msdn给出的说明是:当要求调用方拥有给定 Monitor 的锁的方法被没有该锁的调用方调用时引发的异常。
推测是因为主线程休息的时间太短,抢用Console资源,和Monitor锁定内容中的资源冲突。
可以通过将Thread.Sleep(100)修改为更多毫秒数来避免出错,或者使用以下改进的代码:

    Sub sample13()
        MonitorObj = New Object
        For i As Integer = 0 To 5
            Dim sample13_Thread As New Thread(AddressOf sample13_doALoop2)
            sample13_Thread.Start(i)
        Next

        Thread.Sleep(100)
        Console.ReadKey()
    End Sub


    '修改后的例子
    Sub sample13_doALoop2(ByVal number As Integer)
        Dim counter As Integer = CType(number, Integer)
        Try
            Monitor.TryEnter(MonitorObj, 1000)  '这里的时间不能设置太短,否则会在Exit处发生错误。
            For i As Integer = 1 To 100
                Console.Write(" " & counter)
            Next
        Catch ex As Exception

        Finally
            Monitor.Exit(MonitorObj)
        End Try
    End Sub

 

由于.net平台下C#和vb.NET很相似,本文也可以为C#爱好者提供参考。

学习更多vb.net知识,请参看 vb.net 教程 目录