VB.net学习笔记(二十五)Threading 命名空间
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,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之前,还没有输出就让其失效 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指令的工作就越多。必然对性能产生影响。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |