VB.net学习笔记(二十五)Threading 命名空间


     重要的Thread类在System.Threading中。System.Threading 命名空间提供类和接口,使多线程的编程。 除了用于同步线程活动和访问数据的类 (Mutex, ,Monitor, ,Interlocked, ,AutoResetEvent, ,依此类推),此命名空间包括 ThreadPool 类,它允许您使用的系统提供线程池和 Timer 在线程池线程执行的回调方法的类。
 

1.Thread 类
       Thread类创建和控制线程,设置其优先级并获取其状态。
        进程启动时,公共语言运行时将自动创建一个前台线程执行应用程序代码。 此主前台线程,以及一个进程可以创建一个或多个线程以执行与该进程关联的程序代码的一部分。 在前台或后台中,可以执行这些线程。 此外,您可以使用 ThreadPool 类在由公共语言运行时管理的工作线程上执行代码。
         启动线程 通过提供一个委托,表示该线程是在其类构造函数中执行的方法来启动一个线程。 然后,可以调用 Start 方法开始执行。Thread 构造函数可以采用两个委托类型,具体取决于是否可以将参数传递给要执行的方法.
       线程对象的检索问题您可以使用静态 (Shared 在 Visual Basic 中) CurrentThread 属性来检索对当前执行线程的线程正在执行的代码中的引用。
       前台和后台线程实例 Thread 类表示前台线程或后台线程。 后台线程将与前台线程有一处例外 ︰ 如果所有前台线程已都终止,后台线程不会保留正运行的进程。 一旦所有前台线程已都停止,则运行时将停止所有后台线程,并关闭。
        区域性和线程每个线程都有一个区域性,由表示 CurrentCulture 属性和 UI 区域性,由表示 CurrentUICulture 属性。 当前区域性支持分析和格式设置,字符串比较和排序,诸如区分区域性的操作,还可以控制书写系统和线程使用的日历。 当前 UI 区域性提供用于区分区域性检索资源文件中的资源。
实例化一个新线程时,其区域性和 UI 区域性定义的当前系统区域性和 UI 区域性,而不是区域性和 UI 区域性从中创建新线程的线程。 这意味着,例如,如果当前系统区域性为英语 (美国),主要应用程序线程的当前区域性为法语 (法国),通过调用创建一个新线程的区域性 Thread(ParameterizedThreadStart) 从主线程的构造函数是英语 (美国) 和不是法语 (法国)。

2.线程总览
        Thread的方法:
 
       Thread的属性
 

3.创建线程
      用New Thread( )创建一个新的线程,再用Start执行。
      线程ID:ID是创建线程时操作系统自动生成的,用来标记线程的(线程编号),由操作系统来管理且不得重复(即线程ID是唯一的),此ID只在线程的生存期内有效,线程消失则该ID撤消。
      线程Handle:为一个32位指针。OS有一张维护HANDLE的表单,里面HANDLE的引用计数和有关的属性,尽管相同的句柄一定标识同一线程,但同一线程可能拥有两个打开的句柄,因此,不能用句柄来区分两个线程是否是同一线程。
 

Imports System.Threading
Public Class SimpleThread
    Public Shared Sub main()
        Dim obj As New SimpleThread
        obj.SimpleMethod() '主线程执行
        '-----------
        'Dim t As New Thread(AddressOf obj.SimpleMethod)      '1、ThreadStar上委托调用实例的方法
        Dim ts As New ThreadStart(AddressOf obj.SimpleMethod) '2.同1先指定执行方法,再创建、执行
        Dim t As New Thread(ts)
        '----------
        t.Start()   '线程执行
        Console.Read()
    End Sub
    Public Sub SimpleMethod()
        Dim i As Integer = 5
        Dim x As Integer = 10
        Dim iResult As Integer = i * x
        Console.WriteLine("Result is " & iResult.ToString & " from thread ID:" &
                          Thread.CurrentThread.ManagedThreadId.ToString) '显示托管线程ID
    End Sub
End Class
        例:再看一下新建多个线程时,注意一下ID编号和ID出现的顺序。(运行程序时,本机开了360浏览器、word、OCR软件、优酷PC端、QQ等多个程序)
 
Imports System.Threading
Public Class SimpleThread
    Public Shared Sub main()
        Dim i As Integer
        For i = 1 To 10
            Dim t As New Thread(AddressOf SimpleMethod)
            t.Start()
        Next
        Console.Read()
    End Sub
    Public Shared Sub SimpleMethod()
        Console.WriteLine("Worker Thread: " & Thread.CurrentThread.ManagedThreadId.ToString)
    End Sub
End Class

4.ThreadStart 委托
      表示在 Thread 上执行的方法。Visual Basic 用户在创建线程时可以省略 ThreadStart 构造函数。在传递所用方法时使用 AddressOf 运算符,例如 Dim t As New Thread(AddressOf ThreadProc)。Visual Basic 自动调用 ThreadStart 构造函数。
     简言之:书写代码:Dim t As New Thread(AddressOf ThreadProc),但VB.net内部自动完成的是下面代码:
              Dim t As New Thread(New ThreadStart(AddressOf ThreadProc))
     ThreadStart的优势主要体现在分支选择执行上。
      例:分支选择决定在新的线程上决定执行哪个方法.(1处标注多个委托方法,2处选择哪个,这时并没创建线程实例。只有到了3处才开始构造,然后4处执行)
 
Imports System.Threading
Public Class ThreadStartBranding
    Enum UserClass '枚举
        ClassAdmin
        ClassUser
    End Enum
    Shared Sub main()
        ExecuteFor(UserClass.ClassAdmin)
        ExecuteFor(UserClass.ClassUser)
        Console.Read()
    End Sub
    Shared Sub ExecuteFor(ByVal uc As UserClass)
        Dim ts As ThreadStart
        Dim tsAdmin As New ThreadStart(AddressOf AdminMethod) '1.ThreadStart 委托
        Dim tsUser As New ThreadStart(AddressOf UserMethod)
        If uc = UserClass.ClassUser Then                      '2.选择决定哪个委托方法
            ts = tsUser
        Else
            ts = tsAdmin
        End If
        Dim t As New Thread(ts)                               '3.构造线程
        t.Start()                                             '4.执行
    End Sub
    Shared Sub AdminMethod()
        Console.WriteLine("Admin Method")
    End Sub
    Shared Sub UserMethod()
        Console.WriteLine("User Method")
    End Sub
End Class

5.线程的状态
       线程有多个状态值,创建的线程最初处于Unstarted状态,通过Start方法后线程转为Running状态,中间可以处于睡眠Sleep或挂起Suspend状态,中途还有请求状态:StopRequested(请求停止)、SuspendRequested(请求挂起)、AbortRequested(请求中止),当代码执行完成后自动停止Stopped状态,也可手动或意外中止Aborted状态。线程可以同时处于多个组合状态,比如,请求中止时,线程处于Running与AbortRequested状态。

     线程与另一线程是各行其是的运行,一个线程睡眠并不影响另一个线程的运行。线程里可创建另一个线程,原线程称父线程,创建的线程称子线程。前台线程全部终结后,后台线程即使没结束也会尤如无根之萍,也会随之终结。默认新创建的线程为前台线程。线程停止并不是线程退出

      例:主线程中创建一新线程,主线程睡眠时(1处),新建的线程状态不受影响仍然运行(2处),委托方法执行完成后线程停止运行(3处)但并不是终结(释放资源)。主线程和新建的线程都是前台线程(4处).
 
Imports System.Threading
Public Class ThreadState
    Shared Sub main()
        Dim t As New Thread(AddressOf WorkerFunction)
        t.Start()
        '4、是否后台线程
        Console.WriteLine("Backgroud is " & Thread.CurrentThread.IsBackground & " for main thread.")
        Console.WriteLine("Backgroud is " & t.CurrentThread.IsBackground & " for new  thread.")
        '-------
        While t.IsAlive '主线程每睡眠200毫秒后,时钟中断激活主线程(线程启动后未停止时为真)
            Console.WriteLine("Waiting,main thread is back to sleep.")
            Thread.CurrentThread.Sleep(200)                              '1、主线程睡眠
        End While
        '-------
        Console.WriteLine("Complete,new thread state is " & t.ThreadState.ToString) '3、新线程最后状态
        Console.Read()
    End Sub
    Shared Sub WorkerFunction() '模拟功能,每隔5000毫秒显示新建线程状态
        For i As Integer = 1 To 50000
            If i Mod 5000 = 0 Then
                '2、新建线程的状态(这里的当前线程指的是主线程中创建的新线程)
                Console.WriteLine("Worker: " & Thread.CurrentThread.ThreadState.ToString)
            End If
        Next
        Console.WriteLine("WorkerFunction is completed")
    End Sub
End Class

6.线程的优先级
        线程的优先级决定各个线程之间相对的优先级。ThreadPriority枚举定义可用于设置线程优先级的值,可用的值是:Highest(最高值)、AboveNormal(高于正常值}、Normal(正常值)、BelowNormaK低于正常值)、Lowest(最低值)。在运行时内创建的线程最初被分配 Normal 优先级,而在运行时外创建的线程在进入运行时时将保留其先前的优先级。 可以通过访问线程的 Priority 属性来获取和设置其优先级。
       线程的优先级不影响该线程的状态;在操作系统可以调度该线程之前,该线程的状态必须为 Running。
      例:创建并运行两线程,优先级高的线程优先执行
 
Imports System.Threading
Public Class ThreadPriority
    Public Shared worker1 As Thread
    Public Shared worker2 As Thread
    Public Shared Sub main()
        Console.WriteLine("Entering Sub Main()")
        worker1 = New Thread(AddressOf TestPriority1)
        worker2 = New Thread(AddressOf TestPriority2)
        worker1.Name = "TestPriority1()_Thread"
        worker2.Name = "TestPriority2()_Thread"
        worker2.Priority = Threading.ThreadPriority.Highest

        worker1.Start()
        worker2.Start()
        Console.ReadLine()
    End Sub
    Public Shared Sub TestPriority1()
        Console.WriteLine("-------------------")
        Console.WriteLine("Name:" & worker1.Name)
        Console.WriteLine("State:" & worker1.ThreadState.ToString)
        Console.WriteLine("Priority:" & worker1.Priority.ToString)
    End Sub
    Public Shared Sub TestPriority2()
        Console.WriteLine("===================")
        Console.WriteLine("Name:" & worker2.Name)
        Console.WriteLine("State:" & worker2.ThreadState.ToString)
        Console.WriteLine("Priority:" & worker2.Priority.ToString)
    End Sub
End Class

7.计时器
      由于线程和其余的应用程序代码不按次序运行, 所以无法确定读写共享资源的先后次序。简单的方法是使用计时器:按特定正则间隔执行一个方法,检查在继续下面的操作之前所要求的动作已经完成。
     计时器由两个对象组成,一个是TimerCallback对象,另一个是Timer对象。TimerCallback对象定义在指定间隔执行的动作,而Timer对象本身就是计时器。TimerCallback将一个特定的方法与计时器联系起来, Timer的构造函数(由重载得到)需要4个变量。
                           Timer(TimerCallback, Object, Int64, Int64)或Timer(TimerCallback, Object, TimeSpan, TimeSpan)
      第一个参数是TimerCallback对象,第二个是用来将状态传输给指定的方法的一个对象。后两个参数是在此之后开始计时的周期,以及触发TimerCallback方法调用使用的周期。可以是整数或者长整型或System.TimeSpan对象。
     dueTime 在 callback 参数调用其方法之前延迟的时间量。指定 -1 毫秒以防止启动计时器。指定零 (0) 可立即启动计时器。
     Period 在调用 callback 所引用的方法之间的时间间隔。指定 -1 毫秒可以禁用定期终止。
       例:用计时器(tmr)探测新线程(t)访问共享资源(message)的情况。先新建一个生产文字的线程(1处)并运行,再创建计时器(3处)来探测线程中文本(message)生成情况。计时器每5毫秒触发一次进行查看,无信息时(4处)将显示提示,有信息时就输出并退出计时器(5处),最后6处重置标志使7处循环退出。由于程序运行很快,为了模拟计算费时,在2处浪费10毫秒以达模拟效果。
 
Imports System.Threading
Imports System.Text
Public Class ThreadTimer
    Private Shared message As String
    Private Shared tmr As Timer
    Private Shared complete As Boolean
    Public Shared Sub main()
        Dim obj As New ThreadTimer
        Dim t As New Thread(AddressOf obj.GenerateText)
        t.Start()                                            '1、启动产生文本的线程


        Dim tmrCallBack As New TimerCallback(AddressOf obj.GetText)
        '---------------------------------------              3、每5毫秒触发立即启动方法
        tmr = New Timer(tmrCallBack, Nothing, TimeSpan.Zero, TimeSpan.FromMilliseconds(5))
        Do
            If complete Then Exit Do                          '7、退出
        Loop
        Console.WriteLine("Exiting Main...")
        Console.ReadLine()
    End Sub
    Public Sub GenerateText() '产生字符并接入末尾
        Dim i As Integer
        Dim sb As StringBuilder = New StringBuilder
        For i = 1 To 10
            Thread.Sleep(10)                                  '2、模拟计算耗时
            sb.Insert(sb.Length, "  This is line ")
            sb.Insert(sb.Length, i.ToString)
            sb.Insert(sb.Length, vbCrLf)
        Next
        message = sb.ToString
    End Sub
    Public Sub GetText() '非空时输出字符
        If message Is Nothing Then                             '4、无信息时,提示
            Console.WriteLine(Now.Second.ToString & ":" & Now.Millisecond.ToString &
                              " Not message,waiting...")
            Exit Sub
        End If
        Console.WriteLine("Message is :-------------------------------")
        Console.WriteLine(message)
        tmr.Dispose()                                          '5、计时器释放,失效
        complete = True                                        '6、主程序循环标志退出
    End Sub
End Class
      注意:

       当2处循环次数改为100次时,会发现message会输出两次(尽管代码只有一次),因为是5毫秒触发一次,当一次输出时(100行)时超过5毫秒,这第二次5毫秒后的触发又来了,所以有两次情况。当循环次数改为200时,会有三次message的输出,总之次数越长就会越混乱,最好的办法就是把计时器释放提到message之前,还没有输出就让其失效 

8.线程生线程
一个线程可产生出多个线程,每个方法都可在单独的线程时间片中执行。例,先新添一类

Imports System.Threading
Public Class Car
    Public Sub StartTheEngine()
        Console.WriteLine("Starting the engine!")
        Dim batt As Thread = New Thread(AddressOf CheckTheBattery)
        Dim fuel As Thread = New Thread(AddressOf CheckForFuel)
        Dim eng As Thread = New Thread(AddressOf CheckTheEngine)
        batt.Start()
        fuel.Start()
        eng.Start()
        UseTime()
        Console.WriteLine("Engine is ready!")
    End Sub
    Private Sub CheckTheBattery()
        Console.WriteLine("Checking the Battery!")
        UseTime()
        Console.WriteLine("Finished checking the Battery!")
    End Sub
    Private Sub CheckForFuel()
        Console.WriteLine("Checking for Fuel!")
        UseTime()
        Console.WriteLine("Fuel is available!")
    End Sub
    Private Sub CheckTheEngine()
        Console.WriteLine("Checking the engine!")
        UseTime()
        Console.WriteLine("Finished checking the engine!")
    End Sub
    Private Sub UseTime()
        For i As Integer = 1 To 100000000
        Next
    End Sub
End Class
再主模块中如下(右为模式图):
 
      执行结果如下:
 
        如果还想再分裂生产线程,将上面Car类CheckTheEngine()方法改为:
    Private Sub CheckTheEngine()
        Dim cke As New Engine
        cke.CheckTheEngine()
    End Sub
       并新加类Engine:
Imports System.Threading
Public Class Engine
    Public Sub CheckTheEngine()
        Dim chk1 As Thread = New Thread(AddressOf Check1)
        Dim chk2 As Thread = New Thread(AddressOf Check2)
        chk1.Start()
        chk2.Start()
        Console.WriteLine("Checking the engine!")
        For count As Integer = 1 To 100000000
        Next
        Console.WriteLine("Finished checking the engine!")
    End Sub

    Private Sub Check1()
        Console.WriteLine("Starting the engine check!!")
        For i As Integer = 1 To 100000000
        Next
        Console.WriteLine("Finished engine check 1 !")
    End Sub
    Private Sub Check2()
        Console.WriteLine("Starting the engine check2!")
        For i As Integer = 1 To 100000000
        Next
        Console.WriteLine("Finished engine check2!")
    End Sub
End Class
运行的结果:
 

          注意:创建的线程越多,系统需要保持线程的现场和CPU指令的工作就越多。必然对性能产生影响。

  • 2
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值