【.NET线程--进阶(一)】--线程方法详解
上篇博客从线程的基本概况开始着重讨论了线程,进程,程序之间的区别,然后讨论了线程操作的几个类,并通过实例来说明了线程的创建方法。本篇博客将会带大家更深入的了解线程,介绍线程的基本方法,并通过一个Demo使用委托来调用线程之外的对象。
前篇博客基础:【GDI+编程--番外篇(二)】--从事件看委托
【.NET线程--开篇】--线程从零开始
线程
多线程优缺点
多线程的使用会帮助程序提高响应速度,因为可以同时执行多个任务这样对比一个个的来完成任务来说提高了响应的速度,较之添加多CPU来说多线程提高了强大的技术来执行多个任务。虽然多线程提高了响应速度,但同时牺牲了资源,由于多线程的执行它会占用多个资源,为了避免资源访问的冲突,往往会在每个线程中都会创建自己的资源,这样导致了资源的浪费。另外如果线程过多,则其中大多数线程都不会产生明显的进度,如果大多数当前线程处于一个进程中,则其他进程中的线程的调度频率就会很低。
线程基本方法
下表包括了在线程编程过程中常用的基本方法。
可用于控制单个线程的方法
| 方法 | 操作 |
|---|---|
| Start | 使线程开始运行。 |
| Sleep | 使线程暂停指定的一段时间。 |
| Suspend | 在线程到达安全点时,使其暂停。 |
| Abort | 在线程到达安全点时,使其停止。 |
| Resume | 重新启动挂起的线程 |
| Join | 使当前线程一直等到另一线程完成。 在与超时值一起使用时,如果该线程在分配的时间内完成,此方法将返回 True。 |
Note: 安全点是指代码中公共语言运行时可以安全地执行自动“垃圾回收”的位置。垃圾回收是指释放不再使用的变量并回收内存的过程。 调用线程的 Abort 或 Suspend 方法时,公共语言运行时将对代码进行分析,确定让线程停止运行的适当位置。
Demo1:线程,方法--委托
自己做的一个小Demo来实现多线程,当点击开始按钮后会在文本框中填写数字,与此同时加载进度条,读取进度,点击暂停后线程会停止。另外可以在文本框中输入暂停时间来指定线程暂停时间,在暂停后继续执行。
Demo下载地址:线程常用方法示例
在点击开始按钮后会同时创建两个线程,分别为showNumThread和pBarThread,用来向文本框中写入数字和加载进度条。这里需要说明的是,一般情况下线程内部是不允许调用线程外创建的对象的,创建的两个线程都调用了线程外部的对象,是怎么实现的呢?使用的是委托来异步执行程序来实现了调用线程外部的方法。
- /// <summary>
- /// 开始按钮事件,创建线程并为线程指定方法
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void btnStart_Click(object sender, EventArgs e)
- {
- pBarThread = new Thread(new ThreadStart(this.ExepBarShow)); //创建进度条线程
- showNumThread = new Thread(new ThreadStart(this.ExeShowNum)); //创建显示文本框中的文字线程
- //开始两个已创建的线程
- this.StartThread(showNumThread);
- this.StartThread(pBarThread);
- }
- /// <summary>
- /// 使用委托执行ShowNumToText方法
- /// </summary>
- private void ExeShowNum()
- {
- try
- {
- MethodInvoker mInvoker = new MethodInvoker(this.ShowNumToText); //声明托管委托,并为委托执行执行的方法
- //执行委托方法,向Text中写入文字
- while (true)
- {
- this.BeginInvoke((Delegate)mInvoker); //异步执行执行的委托
- Thread.Sleep(1000); //线程停顿1秒后继续执行
- }
- }
- catch { }
- }
- /// <summary>
- /// 先文本框txtNum中写入文字
- /// </summary>
- private void ShowNumToText()
- {
- i = i + 1; //i累加
- txtNum.Text = txtNum.Text + " " + (i + 1).ToString(); //向txtNum中写入文字
- }
- /// <summary>
- /// 执行pBarShow方法,加载进度条,让进度条读取进度
- /// </summary>
- private void ExepBarShow()
- {
- try
- {
- MethodInvoker mInvoker = new MethodInvoker(this.pBarShow); //声明并创建委托,为委托执行进度
- //异步执行委托
- while (true)
- {
- this.BeginInvoke((Delegate)mInvoker);
- Thread.Sleep(10);
- }
- }
- catch { }
- }
- /// <summary>
- /// 执行进度条读取进度
- /// </summary>
- private void pBarShow()
- {
- this.pgBar.PerformStep();
- }
- /// <summary>
- /// 线程开始方法
- /// </summary>
- /// <param name="th">Thread对象,需要开始的线程</param>
- private void StartThread(Thread th) {
- th.Start();
- }
- /// <summary>
- /// 线程结束方法
- /// </summary>
- /// <param name="th">Thread对象,需要结束的线程</param>
- private void EndThread(Thread th) {
- th.Interrupt(); //中断线程
- th.Abort(); //终止线程
- th = null;
- }
- /// <summary>
- /// 停止线程事件
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void btnStop_Click(object sender, EventArgs e)
- {
- try
- {
- this.TestThead(); //验证线程是否存在,如果没有存在将会抛错
- this.EndThread(this.pBarThread); //结束线程
- this.EndThread(this.showNumThread); //结束线程
- }
- catch (Exception ex)
- {
- //提示错误信息
- MessageBox.Show(ex.Message , "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- }
- /// <summary>
- /// 终止线程事件
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void btnEnd_Click(object sender, EventArgs e)
- {
- try
- {
- this.TestThead(); //验证线程是否创建
- this.EndThread(this.pBarThread);//结束线程
- this.EndThread(this.showNumThread); //结束线程
- txtNum.Text = ""; //清空文本框内容
- i = 0; //数字充值
- this.pgBar.Value = 0;//进度条重置
- }
- catch (Exception ex)
- {
- //显示错误信息
- MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- }
- /// <summary>
- /// 执行指定线程停顿时间
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- private void btnStopMinute_Click(object sender, EventArgs e)
- {
- try
- {
- int j = int.Parse(textBox1.Text); //获取终止的时间
- Thread.Sleep(j); //将线程暂停指定的时间
- }
- catch (Exception ex)
- {
- MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
- }
- }
- /// <summary>
- /// 验证线程是否存在方法
- /// </summary>
- private void TestThead() {
- if (pBarThread ==null)
- {
- throw new Exception ("未创建线程,请创建线程后操作!");
- }
- if (showNumThread == null)
- {
- throw new Exception ("未创建线程,请创建线程后操作!");
- }
- }
Demo2:Join方法使用实例
Join方法能在指定的线程中插入一个线程,当插入的线程执行完成后才会继续执行被插入的线程。.NET为我们重载了此方法,能够为方法传递参数来指定经过的时间,此时该方法的作用与Sleep相类似,执行经过多长时间后来执行被插入的线程。Join方法的灵活运行能够实现线程之间的执行顺序。
- using System;
- using System.Threading;
- namespace TestJoin
- {
- /// <summary>
- /// Join方法验证实例,线程t1使用了join方法,线程t2没有使用join方法
- /// </summary>
- class Program
- {
- static void Main(string[] args)
- {
- //创建新线程,为线程执行行为
- Thread t1 = new Thread(() =>
- {
- Thread.Sleep(1000);
- Console.WriteLine("t1 is ending.");
- });
- t1.Start(); //开始线程
- t1.Join(); //在主线程中插入t1线程,先执行t1,线程后执行主线程
- Console.WriteLine("t1.Join() returned."); //执行主线程,提示t1已经完成
- //创建新线程,为线程执行行为
- Thread t2 = new Thread(() =>
- {
- Thread.Sleep(1000);
- Console.WriteLine("t2 is ending.");
- });
- t2.Start(); //开始线程
- Console.WriteLine("t2.Join() returned."); //执行主线程,提示t1已经完成
- Console.ReadLine();
- }
- }
- }
- /*输出结果:
- *t1 is ending.
- *t1.Join() returned.
- *
- *t2.Join() returned.
- *t2 is ending.
- */
输出结果:
从输出结果上分析可以得出,Join方法将创建的线程插入到了主线程中当执行完后再继续执行主线程,对应到Demo2中是线程t1插入到了主线程中,这样会首先执行t1线程在控制台上打印“t1 is ending”打印完成后t1线程结束,然后继续执行主线程来打印其它的文字。所以我们完全可以说Join方法是将一个线程插入到主线程中,当执行完插入的线程后再继续执行被插入的线程。
结语
线程的优缺点决定了在开发过程中是否使用多线程,另外灵活运行单线程的方法来实现灵活的控制线程,两个Demo使用了线程的基本方法,能够更加深刻的了解它们的使用。下篇博客将会更加深入的讨论线程和线程之间的调用关系,以及如何实现线程间的数据传递及检索。
【.NET线程--进阶(一)】--线程方法详解的更多相关文章
- MySQL服务器线程数的查看方法详解
本文实例讲述了MySQL服务器线程数的查看方法.分享给大家供大家参考,具体如下: mysql重启命令: ? 1 /etc/init.d/mysql restart MySQL服务器的线程数需要在一个合 ...
- (二)线程Thread中的方法详解
1.start() start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果.通过start( ...
- 线程Thread中的方法详解(二)
1.start() start()方法的作用讲得直白点就是通知"线程规划器",此线程可以运行了,正在等待CPU调用线程对象得run()方法,产生一个异步执行的效果.通过start( ...
- “全栈2019”Java多线程第十二章:后台线程setDaemon()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第七章:等待线程死亡join()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第六章:中断线程interrupt()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- “全栈2019”Java多线程第五章:线程睡眠sleep()方法详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...
- java多线程并发(二)--线程的生命周期及方法详解
上篇随笔介绍了线程的相关基础知识以及新启线程的几种方法,本片将继续介绍线程的生命周期及方法详解. 一.线程的生命周期 在Thread代码中,线程的状态被分为6种 public enum State { ...
- 并发编程(六)Object类中线程相关的方法详解
一.notify() 作用:唤醒一个正在等待该线程的锁的线程 PS : 唤醒的线程不会立即执行,它会与其他线程一起,争夺资源 /** * Object类的notify()和notifyAll()方法详 ...
- java线程池的使用与详解
java线程池的使用与详解 [转载]本文转载自两篇博文: 1.Java并发编程:线程池的使用:http://www.cnblogs.com/dolphin0520/p/3932921.html ...
随机推荐
- OneNET麒麟座应用开发之五:获取加速度传感器ADXL345数据
由于数据采集站基本都安装在野外或者楼顶,安装位置以及震动对检测数据的准确性有一定影响.所以想要有一个位置状态数据,正好发现麒麟作上有ADXL345,这样一个数字输出的加速度传感器.如图中红框所示: 1 ...
- OneNET麒麟座应用开发之三:获取温湿度数据
对于大气环境监测来说温湿度也是重要的指标.原本计划使用SHT15来采集温湿度数据,不过在OneNET麒麟开发板上,我们发现已经集成有SHT20温湿度传感器,于是我们就使用它了.如下图的红框处: 我们还 ...
- oracle 各个版本下载地址
Oracle9i Database Release 2 Enterprise/Standard/Personal Edition for Windows NT/2000/XP http://downl ...
- 将模型.pb文件在tensorboard中展示结构
本文介绍将训练好的model.pb文件在tensorboard中展示其网络结构. 1. 从pb文件中恢复计算图 import tensorflow as tf model = 'model.pb' # ...
- 性能测试二十:环境部署之Tomcat多实例部署+日志监控
一个tomcat性能有限,所以需要部署等多个tomcat 单实例部署与windows下类似,项目包放到webapp目录下,启动bin目录下的startup.sh即可启动命令:./startup.sh启 ...
- 基于 OSGi 的面向服务的组件编程,helloworld
基于 OSGi 的面向服务的组件编程 OSGi(Open Services Gateway Initiative,开放服务网关协议)提供了一个面向服务组件的编程模型,基于 OSGi 编程,具有模块化, ...
- day8--socketserver回顾
sockeserver主要实现多并发的情况,我们知道,socket只能一对一用户进行交互,如何实现一对多交互,socketserver就是用来解决这个问题的. socketserver--共有这么几种 ...
- BZOJ1966 [Ahoi2005]VIRUS 病毒检测 动态规划
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - BZOJ1966 题意概括 现在有一些串和一个病毒模板.让你统计非病毒串的总数.串个数<=500. 串由 ...
- Docker 配置固定IP及桥接的实现方法(转载)
这篇文章主要介绍了Docker 配置固定IP和桥接的实现方法的相关资料,这里详细介绍了Docker 的四种网络模式及如何实现桥接的案例,需要的朋友可以参考下 docker默认使用bridge模式,通过 ...
- 002.Heartbeat部署及httpd高可用
一 前期准备 1.1 依赖准备 编译安装需要依赖的包,如gcc等: yum -y install gcc gcc-c++ make glibc kernel-devel kernel-headers ...