zoukankan      html  css  js  c++  java
  • 以ThreadStart方式实现多线程

    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("\n{0}'s age is {1}!\nAsync 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("\nAsync 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("\nAsync 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 }
    复制代码

    运行结果如下

  • 相关阅读:
    uni-app引入自己ui写的icon
    2020.07.17
    读uni-app
    图片上传,配置php以及vue简单实现
    vue子给父组件传值
    vue父子传值以及监听这个值,把值拿到子组件使用不报警告
    vue局部跳转,实现一个类似选项卡tab功能
    vuex的一个demo,数据拿到界面上
    vue-day06&day07----路由、路由常用的配置项、vue路由的内置组件、vue路由跳转的方式、路由传值、路由解耦(路由传值的一种方式)、编程式导航、嵌套路由children、路由元信息meta、路由生命周期(路由守卫)、路由懒加载、vue/cli、webpack配置alias、vue/cli中配置alias、vue-router底层原理、单页面开发的缺点、路由报错
    vue-day06----过渡&动画(transition)、axios、axios以post方式请求数据、axios常用的配置项、axios拦截器、qs处理数据、vue中async和await的使用
  • 原文地址:https://www.cnblogs.com/meilibao/p/2725736.html
Copyright © 2011-2022 走看看