3.1 使用ThreadStart委托
这 里先以一个例子体现一下多线程带来的好处,首先在Message类中建立一个方法ShowMessage(),里面显示了当前运行线程的Id,并使用 Thread.Sleep(int ) 方法模拟部分工作。在main()中通过ThreadStart委托绑定Message对象的ShowMessage()方法,然后通过 Thread.Start()执行异步方法。
1 public class Message 2 { 3 public void ShowMessage() 4 { 5 string message = string.Format("Async threadId is :{0}", 6 Thread.CurrentThread.ManagedThreadId); 7 Console.WriteLine(message); 8 9 for (int n = 0; n < 10; n++) 10 { 11 Thread.Sleep(300); 12 Console.WriteLine("The number is:" + n.ToString()); 13 } 14 } 15 } 16 17 class Program 18 { 19 static void Main(string[] args) 20 { 21 Console.WriteLine("Main threadId is:"+ 22 Thread.CurrentThread.ManagedThreadId); 23 Message message=new Message(); 24 Thread thread = new Thread(new ThreadStart(message.ShowMessage)); 25 thread.Start(); 26 Console.WriteLine("Do something ..........!"); 27 Console.WriteLine("Main thread working is complete!"); 28 29 } 30 }请注意运行结果,在调用Thread.Start()方法后,系统以异步方式运行Message.ShowMessage(),而主线程的操作是继续执行的,在Message.ShowMessage()完成前,主线程已完成所有的操作。
3.2 使用ParameterizedThreadStart委托
ParameterizedThreadStart 委托与ThreadStart委托非常相似,但ParameterizedThreadStart委托是面向带参数方法的。注意 ParameterizedThreadStart 对应方法的参数为object,此参数可以为一个值对象,也可以为一个自定义对象。
1 public class Person 2 { 3 public string Name 4 { 5 get; 6 set; 7 } 8 public int Age 9 { 10 get; 11 set; 12 } 13 } 14 15 public class Message 16 { 17 public void ShowMessage(object person) 18 { 19 if (person != null) 20 { 21 Person _person = (Person)person; 22 string message = string.Format(" {0}'s age is {1}! Async threadId is:{2}", 23 _person.Name,_person.Age,Thread.CurrentThread.ManagedThreadId); 24 Console.WriteLine(message); 25 } 26 for (int n = 0; n < 10; n++) 27 { 28 Thread.Sleep(300); 29 Console.WriteLine("The number is:" + n.ToString()); 30 } 31 } 32 } 33 34 class Program 35 { 36 static void Main(string[] args) 37 { 38 Console.WriteLine("Main threadId is:"+Thread.CurrentThread.ManagedThreadId); 39 40 Message message=new Message(); 41 //绑定带参数的异步方法运行结果:
42 Thread thread = new Thread(new ParameterizedThreadStart(message.ShowMessage)); 43 Person person = new Person(); 44 person.Name = "Jack"; 45 person.Age = 21; 46 thread.Start(person); //启动异步线程
47 48 Console.WriteLine("Do something ..........!"); 49 Console.WriteLine("Main thread working is complete!"); 50 51 } 52 }
3.3 前台线程与后台线程
注意以上两个例子都没有使用Console.ReadKey(),但系统依然会等待异步线程完成后才会结束。这是因为使用Thread.Start()启动的线程默认为前台线程,而系统必须等待所有前台线程运行结束后,应用程序域才会自动卸载。
在第二节曾经介绍过线程Thread有一个属性IsBackground,通过把此属性设置为true,就可以把线程设置为后台线程!这时应用程序域将在主线程完成时就被卸载,而不会等待异步线程的运行。
3.4 挂起线程
为了等待其他后台线程完成后再结束主线程,就可以使用Thread.Sleep()方法。
1 public class Message 2 { 3 public void ShowMessage() 4 { 5 string message = string.Format(" Async threadId is:{0}", 6 Thread.CurrentThread.ManagedThreadId); 7 Console.WriteLine(message); 8 for (int n = 0; n < 10; n++) 9 { 10 Thread.Sleep(300); 11 Console.WriteLine("The number is:" + n.ToString()); 12 } 13 } 14 } 15 16 class Program 17 { 18 static void Main(string[] args) 19 { 20 Console.WriteLine("Main threadId is:"+ 21 Thread.CurrentThread.ManagedThreadId); 22 23 Message message=new Message(); 24 Thread thread = new Thread(new ThreadStart(message.ShowMessage)); 25 thread.IsBackground = true; 26 thread.Start(); 27 28 Console.WriteLine("Do something ..........!"); 29 Console.WriteLine("Main thread working is complete!"); 30 Console.WriteLine("Main thread sleep!"); 31 Thread.Sleep(5000); 32 } 33 }
运行结果如下,此时应用程序域将在主线程运行5秒后自动结束
但 系统无法预知异步线程需要运行的时间,所以用通过Thread.Sleep(int)阻塞主线程并不是一个好的解决方法。有见及此,.NET专门为等待异 步线程完成开发了另一个方法thread.Join()。把上面例子中的最后一行Thread.Sleep(5000)修改为 thread.Join() 就能保证主线程在异步线程thread运行结束后才会终止。
3.5 Suspend 与 Resume (慎用)
Thread.Suspend() 与 Thread.Resume()是在Framework1.0 就已经存在的老方法了,它们分别可以挂起、恢复线程。但在Framework2.0中就已经明确排斥这两个方法。这是因为一旦某个线程占用了已有的资源, 再使用Suspend()使线程长期处于挂起状态,当在其他线程调用这些资源的时候就会引起死锁!所以在没有必要的情况下应该避免使用这两个方法。
3.6 终止线程
若想终止正在运行的线程,可以使用Abort()方法。在使用Abort()的时候,将引发一个特殊异常 ThreadAbortException 。
若想在线程终止前恢复线程的执行,可以在捕获异常后 ,在catch(ThreadAbortException ex){...} 中调用Thread.ResetAbort()取消终止。
而使用Thread.Join()可以保证应用程序域等待异步线程结束后才终止运行。
1 static void Main(string[] args) 2 { 3 Console.WriteLine("Main threadId is:" + 4 Thread.CurrentThread.ManagedThreadId); 5 6 Thread thread = new Thread(new ThreadStart(AsyncThread)); 7 thread.IsBackground = true; 8 thread.Start(); 9 thread.Join(); 10 11 } 12 13 //以异步方式调用
14 static void AsyncThread() 15 { 16 try 17 { 18 string message = string.Format(" Async threadId is:{0}", 19 Thread.CurrentThread.ManagedThreadId); 20 Console.WriteLine(message); 21 22 for (int n = 0; n < 10; n++) 23 { 24 //当n等于4时,终止线程
25 if (n >= 4) 26 { 27 Thread.CurrentThread.Abort(n); 28 } 29 Thread.Sleep(300); 30 Console.WriteLine("The number is:" + n.ToString()); 31 } 32 } 33 catch (ThreadAbortException ex) 34 { 35 //输出终止线程时n的值
36 if (ex.ExceptionState != null) 37 Console.WriteLine(string.Format("Thread abort when the number is: {0}!", 38 ex.ExceptionState.ToString())); 39 40 //取消终止,继续执行线程
41 Thread.ResetAbort(); 42 Console.WriteLine("Thread ResetAbort!"); 43 } 44 45 //线程结束
46 Console.WriteLine("Thread Close!"); 47 }
运行结果如下