上篇博客从线程的基本概况开始着重讨论了线程,进程,程序之间的区别,然后讨论了线程操作的几个类,并通过实例来说明了线程的创建方法。本篇博客将会带大家更深入的了解线程,介绍线程的基本方法,并通过一个Demo使用委托来调用线程之外的对象。

前篇博客基础:【GDI+编程--番外篇(二)】--从事件看委托
                               【.NET线程--开篇】--线程从零开始

线程

多线程优缺点

多线程的使用会帮助程序提高响应速度,因为可以同时执行多个任务这样对比一个个的来完成任务来说提高了响应的速度,较之添加多CPU来说多线程提高了强大的技术来执行多个任务。虽然多线程提高了响应速度,但同时牺牲了资源,由于多线程的执行它会占用多个资源,为了避免资源访问的冲突,往往会在每个线程中都会创建自己的资源,这样导致了资源的浪费。另外如果线程过多,则其中大多数线程都不会产生明显的进度,如果大多数当前线程处于一个进程中,则其他进程中的线程的调度频率就会很低。

线程基本方法

下表包括了在线程编程过程中常用的基本方法。

可用于控制单个线程的方法

方法 操作
Start  使线程开始运行。
Sleep 使线程暂停指定的一段时间。
Suspend 在线程到达安全点时,使其暂停。
Abort  在线程到达安全点时,使其停止。
Resume 重新启动挂起的线程
Join 使当前线程一直等到另一线程完成。 在与超时值一起使用时,如果该线程在分配的时间内完成,此方法将返回 True。

 

       Note: 安全点是指代码中公共语言运行时可以安全地执行自动“垃圾回收”的位置。垃圾回收是指释放不再使用的变量并回收内存的过程。 调用线程的 Abort 或 Suspend 方法时,公共语言运行时将对代码进行分析,确定让线程停止运行的适当位置。

Demo1:线程,方法--委托

自己做的一个小Demo来实现多线程,当点击开始按钮后会在文本框中填写数字,与此同时加载进度条,读取进度,点击暂停后线程会停止。另外可以在文本框中输入暂停时间来指定线程暂停时间,在暂停后继续执行。

Demo下载地址:线程常用方法示例

在点击开始按钮后会同时创建两个线程,分别为showNumThread和pBarThread,用来向文本框中写入数字和加载进度条。这里需要说明的是,一般情况下线程内部是不允许调用线程外创建的对象的,创建的两个线程都调用了线程外部的对象,是怎么实现的呢?使用的是委托来异步执行程序来实现了调用线程外部的方法。

  1. /// <summary>
  2. /// 开始按钮事件,创建线程并为线程指定方法
  3. /// </summary>
  4. /// <param name="sender"></param>
  5. /// <param name="e"></param>
  6. private void btnStart_Click(object sender, EventArgs e)
  7. {
  8. pBarThread = new Thread(new ThreadStart(this.ExepBarShow)); //创建进度条线程
  9. showNumThread = new Thread(new ThreadStart(this.ExeShowNum));   //创建显示文本框中的文字线程
  10. //开始两个已创建的线程
  11. this.StartThread(showNumThread);
  12. this.StartThread(pBarThread);
  13. }
  14. /// <summary>
  15. /// 使用委托执行ShowNumToText方法
  16. /// </summary>
  17. private void ExeShowNum()
  18. {
  19. try
  20. {
  21. MethodInvoker mInvoker = new MethodInvoker(this.ShowNumToText); //声明托管委托,并为委托执行执行的方法
  22. //执行委托方法,向Text中写入文字
  23. while (true)
  24. {
  25. this.BeginInvoke((Delegate)mInvoker);   //异步执行执行的委托
  26. Thread.Sleep(1000);     //线程停顿1秒后继续执行
  27. }
  28. }
  29. catch { }
  30. }
  31. /// <summary>
  32. /// 先文本框txtNum中写入文字
  33. /// </summary>
  34. private void ShowNumToText()
  35. {
  36. i = i + 1;  //i累加
  37. txtNum.Text = txtNum.Text + " " + (i + 1).ToString();   //向txtNum中写入文字
  38. }
  39. /// <summary>
  40. /// 执行pBarShow方法,加载进度条,让进度条读取进度
  41. /// </summary>
  42. private void ExepBarShow()
  43. {
  44. try
  45. {
  46. MethodInvoker mInvoker = new MethodInvoker(this.pBarShow);  //声明并创建委托,为委托执行进度
  47. //异步执行委托
  48. while (true)
  49. {
  50. this.BeginInvoke((Delegate)mInvoker);
  51. Thread.Sleep(10);
  52. }
  53. }
  54. catch { }
  55. }
  56. /// <summary>
  57. /// 执行进度条读取进度
  58. /// </summary>
  59. private void pBarShow()
  60. {
  61. this.pgBar.PerformStep();
  62. }
  63. /// <summary>
  64. /// 线程开始方法
  65. /// </summary>
  66. /// <param name="th">Thread对象,需要开始的线程</param>
  67. private void StartThread(Thread th) {
  68. th.Start();
  69. }
  70. /// <summary>
  71. /// 线程结束方法
  72. /// </summary>
  73. /// <param name="th">Thread对象,需要结束的线程</param>
  74. private void EndThread(Thread th) {
  75. th.Interrupt(); //中断线程
  76. th.Abort(); //终止线程
  77. th = null;
  78. }
  79. /// <summary>
  80. /// 停止线程事件
  81. /// </summary>
  82. /// <param name="sender"></param>
  83. /// <param name="e"></param>
  84. private void btnStop_Click(object sender, EventArgs e)
  85. {
  86. try
  87. {
  88. this.TestThead();   //验证线程是否存在,如果没有存在将会抛错
  89. this.EndThread(this.pBarThread);    //结束线程
  90. this.EndThread(this.showNumThread); //结束线程
  91. }
  92. catch (Exception ex)
  93. {
  94. //提示错误信息
  95. MessageBox.Show(ex.Message , "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
  96. }
  97. }
  98. /// <summary>
  99. /// 终止线程事件
  100. /// </summary>
  101. /// <param name="sender"></param>
  102. /// <param name="e"></param>
  103. private void btnEnd_Click(object sender, EventArgs e)
  104. {
  105. try
  106. {
  107. this.TestThead();   //验证线程是否创建
  108. this.EndThread(this.pBarThread);//结束线程
  109. this.EndThread(this.showNumThread); //结束线程
  110. txtNum.Text = "";   //清空文本框内容
  111. i = 0;  //数字充值
  112. this.pgBar.Value = 0;//进度条重置
  113. }
  114. catch (Exception ex)
  115. {
  116. //显示错误信息
  117. MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
  118. }
  119. }
  120. /// <summary>
  121. /// 执行指定线程停顿时间
  122. /// </summary>
  123. /// <param name="sender"></param>
  124. /// <param name="e"></param>
  125. private void btnStopMinute_Click(object sender, EventArgs e)
  126. {
  127. try
  128. {
  129. int j = int.Parse(textBox1.Text);   //获取终止的时间
  130. Thread.Sleep(j);    //将线程暂停指定的时间
  131. }
  132. catch (Exception ex)
  133. {
  134. MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
  135. }
  136. }
  137. /// <summary>
  138. /// 验证线程是否存在方法
  139. /// </summary>
  140. private void TestThead() {
  141. if (pBarThread ==null)
  142. {
  143. throw new Exception ("未创建线程,请创建线程后操作!");
  144. }
  145. if (showNumThread  == null)
  146. {
  147. throw new Exception ("未创建线程,请创建线程后操作!");
  148. }
  149. }

Demo2:Join方法使用实例

Join方法能在指定的线程中插入一个线程,当插入的线程执行完成后才会继续执行被插入的线程。.NET为我们重载了此方法,能够为方法传递参数来指定经过的时间,此时该方法的作用与Sleep相类似,执行经过多长时间后来执行被插入的线程。Join方法的灵活运行能够实现线程之间的执行顺序。

  1. using System;
  2. using System.Threading;
  3. namespace TestJoin
  4. {
  5. /// <summary>
  6. /// Join方法验证实例,线程t1使用了join方法,线程t2没有使用join方法
  7. /// </summary>
  8. class Program
  9. {
  10. static void Main(string[] args)
  11. {
  12. //创建新线程,为线程执行行为
  13. Thread t1 = new Thread(() =>
  14. {
  15. Thread.Sleep(1000);
  16. Console.WriteLine("t1 is ending.");
  17. });
  18. t1.Start(); //开始线程
  19. t1.Join();  //在主线程中插入t1线程,先执行t1,线程后执行主线程
  20. Console.WriteLine("t1.Join() returned.");   //执行主线程,提示t1已经完成
  21. //创建新线程,为线程执行行为
  22. Thread t2 = new Thread(() =>
  23. {
  24. Thread.Sleep(1000);
  25. Console.WriteLine("t2 is ending.");
  26. });
  27. t2.Start(); //开始线程
  28. Console.WriteLine("t2.Join() returned.");   //执行主线程,提示t1已经完成
  29. Console.ReadLine();
  30. }
  31. }
  32. }
  33. /*输出结果:
  34. *t1 is ending.
  35. *t1.Join() returned.
  36. *
  37. *t2.Join() returned.
  38. *t2 is ending.
  39. */

 输出结果:
               

从输出结果上分析可以得出,Join方法将创建的线程插入到了主线程中当执行完后再继续执行主线程,对应到Demo2中是线程t1插入到了主线程中,这样会首先执行t1线程在控制台上打印“t1 is ending”打印完成后t1线程结束,然后继续执行主线程来打印其它的文字。所以我们完全可以说Join方法是将一个线程插入到主线程中,当执行完插入的线程后再继续执行被插入的线程。

结语

线程的优缺点决定了在开发过程中是否使用多线程,另外灵活运行单线程的方法来实现灵活的控制线程,两个Demo使用了线程的基本方法,能够更加深刻的了解它们的使用。下篇博客将会更加深入的讨论线程和线程之间的调用关系,以及如何实现线程间的数据传递及检索。

【.NET线程--进阶(一)】--线程方法详解的更多相关文章

  1. MySQL服务器线程数的查看方法详解

    本文实例讲述了MySQL服务器线程数的查看方法.分享给大家供大家参考,具体如下: mysql重启命令: ? 1 /etc/init.d/mysql restart MySQL服务器的线程数需要在一个合 ...

  2. (二)线程Thread中的方法详解

    1.start() start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果.通过start( ...

  3. 线程Thread中的方法详解(二)

    1.start() start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果.通过start( ...

  4. “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  5. “全栈2019”Java多线程第七章:等待线程死亡join()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  6. “全栈2019”Java多线程第六章:中断线程interrupt()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  7. “全栈2019”Java多线程第五章:线程睡眠sleep()方法详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  8. java多线程并发(二)--线程的生命周期及方法详解

    上篇随笔介绍了线程的相关基础知识以及新启线程的几种方法,本片将继续介绍线程的生命周期及方法详解. 一.线程的生命周期 在Thread代码中,线程的状态被分为6种 public enum State { ...

  9. 并发编程(六)Object类中线程相关的方法详解

    一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详 ...

  10. java线程池的使用与详解

    java线程池的使用与详解 [转载]本文转载自两篇博文:  1.Java并发编程:线程池的使用:http://www.cnblogs.com/dolphin0520/p/3932921.html   ...

随机推荐

  1. charles mock方法及问题

    一. 抓包后修改返回数据1.生成一个完成的请求返回信息1.charles抓取一个完整的请求,返回数据2.然后找到该请求,右键“save response”,将该完整请求返回文件保存至本地3.修改本地需 ...

  2. TestNG配置注解

    以下是TestNG支持的注释列表: 注解 描述 @BeforeSuite 在该套件的所有测试都运行在注释的方法之前,仅运行一次. @AfterSuite 在该套件的所有测试都运行在注释方法之后,仅运行 ...

  3. zabbix server+agent+proxy搭建性能监控平台

    这是新找到了配置文件配置方法但未尝试 每个模块工作职责: Zabbix Server:负责接收agent发送的报告信息的核心组件,所有配置,统计数据及操作数据均由其组织进行: Database Sto ...

  4. 我靠,上班eclipse看糗事百科

    package test; import java.io.BufferedReader; import java.io.InputStreamReader; import java.net.URL; ...

  5. Javascript面向对象基础(二)

    一: 用定义函数的方式定义类在面向对象的思想中,最核心的概念之一就是类.一个类表示了具有相似性质的一类事物的抽象,通过实例化一个类,可以获得属于该类的一个实例,即对象.在JavaScript中定义一个 ...

  6. java -d

    DB_SERVER_URL="-Ddatasource.driver=oracle.jdbc.OracleDriver -Ddatasource.url=jdbc:oracle:thin:@ ...

  7. POJ 1995 Raising Modulo Numbers (快速幂)

    题意: 思路: 对于每个幂次方,将幂指数的二进制形式表示,从右到左移位,每次底数自乘,循环内每步取模. #include <cstdio> typedef long long LL; LL ...

  8. #1 // BZOJ 4361 isn

    Description 给出一个长度为n的序列A(A1,A2...AN).如果序列A不是非降的,你必须从中删去一个数, 这一操作,直到A非降为止.求有多少种不同的操作方案,答案模10^9+7.   题 ...

  9. C#编程语法积累(二)

    9.Lambda表达式 [1]Lambda表达式缩写推演,如下图: [2]Lambda语句:=>右边有一个语句块(大括号"{}"):Lambda表达式:=>右边只有一个 ...

  10. python全栈开发day37-html

    web准备总结: 结构标准:相当于人的身体.html就是用来制作网页的. 表现标准: 相当于人的衣服.css就是对网页进行美化的. 行为标准: 相当于人的动作.JS就是让网页动起来,具有生命力的 1. ...