多线程之旅(Thread)

在上篇文章中我们已经知道了多线程是什么了,那么它到底可以干嘛呢?这里特别声明一个前面的委托没看的同学可以到上上上篇博文查看,因为多线程要经常使用到委托源码一、异步、同步1.同步(在计算的理解总是要你措不及防,同步当线程做完一件事情之后,才会执行后续动作),同步方法慢,只有一个线程执行,异步方法快,因为多个线程一起干活,但是两者并不是线性增长,当我们的异步线程占有的资源越来越多了,会导致资源可能不够,其次线程过多CPU也是需要管理成本的,所以不是越多越好。2.异步(可以同时执行多个任务,在同样的时间,执行不同的任务),同步方法卡界面(UI),因为我们的主线程(UI)忙于计算造成了堵塞了。异步方法不卡界面,计算任务交给了子线程完成。winform中体现的玲玲精致。(你品,你细品),web 可以异步的处理一起其他的任务,比如给用户发邮箱(我们的BS结构的,每次访问都是一个子线程,当我们的代码写的比较糟糕,是不是加载比较慢呢哈哈)。异步多线程无序,执行的先后无序,执行的时间不确定,结束也不确定,所以我们很难通过执行时间和先后顺序控制,异步的执行顺序。二、初识Thread属性名称说明CurrentContext获取线程正在其中执行的当前上下文。CurrentThread获取当前正在运行的线程。ExecutionContext获取一个 ExecutionContext 对象,该对象包含有关当前线程的各种上下文的信息。IsAlive获取一个值,该值指示当前线程的执行状态。IsBackground获取或设置一个值,该值指示某个线程是否为后台线程。IsThreadPoolThread获取一个值,该值指示线程是否属于托管线程池。ManagedThreadId获取当前托管线程的唯一标识符。Name获取或设置线程的名称。Priority获取或设置一个值,该值指示线程的调度优先级。ThreadState获取一个值,该值包含当前线程的状态。Thread 中包括了多个方法来控制线程的创建、挂起、停止、销毁,后面的例子中会经常使用。方法名称说明Abort()    终止本线程。GetDomain()返回当前线程正在其中运行的当前域。GetDomainId()返回当前线程正在其中运行的当前域Id。Interrupt()中断处于 WaitSleepJoin 线程状态的线程。Join()已重载。 阻塞调用线程,直到某个线程终止时为止。Resume()继续运行已挂起的线程。Start()  执行本线程。Suspend()挂起当前线程,如果当前线程已属于挂起状态则此不起作用Sleep()  把正在运行的线程挂起一段时间。1.Thread是我们.NET 1.0 给我们提供的多线程类,可以创建,和控制多线程,Thread类构造函数为接受ThreadStart和ParameterizedThreadStart类型的委托参数,下面有请代码神君。

/// <summary> /// 使用Thread 创建多线程 /// </summary> public static void Show() { //实例化创建线程 无参无返回值 Thread thread = new Thread(() => { Console.WriteLine("我是多线程"); }); thread.Start(); //创建5个线程1 for (int i = 0; i < 5; i++) { //这个之所以创建一个k,后面线程不安全会说到 var k = i; //这是一个有参数无返回值多线程 new Thread(x => Running(Convert.ToInt32(x))).Start(k); } Console.Read(); } /// <summary> /// 一个执行需要长时间的任务 /// </summary> static void Running(int s) { Console.WriteLine("**********************************"); Console.WriteLine("执行开始啦" + s); Console.WriteLine("获取当前执行的线程ID:" + Thread.CurrentThread.ManagedThreadId.ToString()); var j = 0; for (int i = 0; i < 1000000000; i++) { j++; } Console.WriteLine("执行结束啦" + s); }View Code

二、渐入佳境1.运行上面的代码,可以看到线程的无序性,虽然我们的0最先开始执行的,但是不是第一个结束的,这个是因为我们每个线程执行的时间的不确定性。这里也要特别说明为什么Thread构造函数传递的是ThreadStart和ParameterizedThreadStart类型的委托参数,为什么不是Action ,Func,答案就是.NET 1.0的时候还没有Action 、Func。ThreadStart委托是一个无参无返回值上代码中我们创建了,ParameterizedThreadStart委托是一个有参数无返回值,但是我们可以看到我们的参数是一个object类型,是一个不安全的参数(当时泛型也没有出来)当然为了防止这问题,我们也是想到了方法,那就是我们可以通过一个泛型类,帮我们限制参数类型。

/// <summary> /// 防止参数不安全 /// </summary> public static void Show5() { //我们创建一个泛型类,限制我们的类型 MyThread<string> mythread = new MyThread<string>("Thread_child"); //将我们的方法传递,进去 Thread th3 = new Thread(mythread.ThreadChild); //启动线程 th3.Start(); } /// <summary> /// 创建一个泛型类 /// </summary> /// <typeparam name="T"></typeparam> class MyThread<T> { private T data; public MyThread(T data) { this.data = data; } public void ThreadChild() { Console.WriteLine("Child Thread Start! Result:{0}", data); } }View Code2.我们在上面还提供了其他的方法,但是这些方法已经不建议使用了,现在已经弃用了,因为我们无法精确地控制线程的开启与暂停,当我们将线程挂起的时候,同时也会挂起线程使用的资源,会导致死锁,不建议使用。将线程销毁也不建议    不一定及时/有些动作发出收不回来。(这里我使用的是.net Core 3.1 执行直接报错了哈哈)

/// <summary> /// 使用Thread 线程挂起、唤醒线程、销毁,方式是抛异常、取消Abort异常 /// </summary> public static void Show1() { //创建一个Thread 线程 Thread thread = new Thread(() => { Running(); }); //开启线程 thread.Start(); //这个是线程挂起 //thread.Suspend(); //唤醒线程 //thread.Resume(); //上面的两个方法,现在已经弃用了,因为我们无法精确地控制线程的开启与暂停 //当我们将线程挂起的时候,同时也会挂起线程使用的资源,会导致死锁,不建议使用 try { //将线程销毁 //也不建议 不一定及时/有些动作发出收不回来 thread.Abort(); } catch (Exception) { //静态方法将线程异常取消继续工作 Thread.ResetAbort(); } Console.Read(); }View Code

3.线程优先级,当然我们的线程是一个无序的,也有控制线程执行的权重,但是这个优先级不是绝对的,因为线程的执行顺序还是看我们的CPU爸爸的,但是我们可以利用Priority属性做线程的权重执行,使用也很简单

/// <summary> /// 使用Thread 线程的优先级(但是执行还是看CPU,可以做优先级,但是不是绝对优先) /// </summary> public static void Show3() { //创建一个Thread 线程 Thread thread = new Thread(() => { Running(); }); thread.Start(); //thread.Priority属性可以设置线程的优先级关系 thread.Priority = ThreadPriority.Highest; Console.WriteLine("执行完啦啦啦啦啦啦啦啦啦啦啦拉拉"); Console.Read(); }View Code4.前台线程、后台线程(这个字面意思,还是和我们的理解是不一样的)我们设置IsBackground控制线程是否(前/后)台线程。默认是前台线程,启动之后一定要完成任务的,阻止进程退出。指定后台线程:随着进程退出。

三、多线程起飞1、异步回调1.我们的Thread没有给我提供异步回调的功能,没办法需要自己造轮子了,我们可以先想一下回调的需求是什么,需求分析:当我们的线程任务执行完之后需要之后某些方法。我们细品一下,我们要执行完之后,在执行一个人任务,那就是同步执行异步方法了吧。我们在子线程中怎么同步执行呢?下面的代码就实现了回调功能不管我们执行多少次回调总会在任务后面执行。

/// <summary> /// 异步回调执行 /// </summary> public static void Show6() { //创建一个任务委托 ThreadStart threadStart = () => { Console.WriteLine("我是任务"); }; //创建一个回调执行的委托 Action action = () => { Console.WriteLine("哈哈,我就是你们的回调方法哈,记得双击么么哒"); Console.WriteLine("*********************************************"); }; ThreadWithCallback(threadStart, action); Console.ReadLine(); }/// <summary> /// 回调封装 无返回值 /// </summary> /// <param name="start"></param> /// <param name="callback">回调</param> private static void ThreadWithCallback(ThreadStart start, Action callback) { Thread thread = new Thread(() => { start.Invoke(); callback.Invoke(); }); thread.Start(); }View Code

2、返回参数1.当然我们使用线程需要返回参数,但是我们的Thread没有给我们提供返回值的委托和方法,这个要莫子搞罗?当然我们先分析需求,我们要获取返回值是不是要等线程执行之后呢?好的线程执行我们可以使用Join堵塞线程等它执行完毕,但是我们要怎么获取返回值呢?对了我们可以创建一个变量,我们的线程给变量赋值吗?

/// <summary> /// 异步返回值 /// </summary> public static void Show7() { //创建一个委托 Func<string> func = () => { return "我是返回值"; }; //获取执行结果 Console.WriteLine(ThreadWithReturn(func).Invoke()); Console.ReadLine(); }/// <summary> /// 有返回值封装(请根据本案例自行封装回调) /// </summary> /// <typeparam name="T">返回值类型</typeparam> /// <param name="func">需要子线程执行的方法</param> /// <returns></returns> private static Func<T> ThreadWithReturn<T>(Func<T> func) { //初始化一个泛型,限制我们的类型 T t = default(T); ThreadStart newStart = () => { //线程给变量赋值 t = func.Invoke(); }; //创建线程 Thread thread = new Thread(newStart); //执行线程 thread.Start(); //创建一个委托 无参有返回值,执行委托会发生执行线程等待堵塞 //当线程执行完之后,也就是说线程已经给变量t赋值了,我们就返回t return new Func<T>(() => { thread.Join(); return t; }); }View Code

四、Thread总结1.大家是不是觉得多线程很酷呢?哈哈我刚刚学的时候也是激动的心颤抖的手。当然文章中我们介绍了很多API的使用,大家可以动手试试,API的使用是小事,最重要的是我们的思路,到我们看到回调封装和返回值封装,我们都是利用了多线程的一些特性,来完成的这些功能拓展的。我们宏观的看多线程感觉很恐怖,但是在我们做回调函数的时候是不是感觉有一种微观看法,线程执行的内部也是同步的执行哪些方法的。好了今天就写到这里昨天晚上9点多就睡了,早起撸个文章美滋滋。当然多线程还有讲完的,才说道了.NET 1.0哈哈,后续的文章也会写出来。

(0)

相关推荐

  • 一文说通C#中的异步编程

    天天写,不一定就明白. 又及,前两天看了一个关于同步方法中调用异步方法的文章,里面有些概念不太正确,所以整理了这个文章.   一.同步和异步. 先说同步. 同步概念大家都很熟悉.在异步概念出来之前,我 ...

  • .NET异步和多线程系列(二)- Thread和ThreadPool

    一.Thread类 C#里面的多线程:Thread类是C#语言对线程对象的一个封装. 首先看下如何开启线程,执行委托的内容: /// <summary>/// 一个比较耗时耗资源的私有方法 ...

  • 多线程之旅(ThreadPool 线程池)

    一.什么是ThreadPool 线程池(源码) 1.线程池顾名思义,有我们的系统创建一个容器装载着我们的线程,由CLR控制的所有AppDomain共享.线程池可用于执行任务.发送工作项.处理异步 I/ ...

  • C#多线程之旅

    多线程之旅(1)_线程同步之AutoResetEvent和ManualResetEvent的区别.用法--附C#源码示例 多线程之旅(2)_创建一个属于自己的精简线程池_线程调度策略--附C#源码 多 ...

  • 多线程之旅(10)_QueueUserWorkItem和UnsafeQueueUserWorkItem的区别

    转载:https://blog.csdn.net/yangwohenmai1/article/details/90490880 这是个比较冷门的点,是我在写多线程之旅(2)_创建一个属于自己的精简线程 ...

  • 旅界专研 | 文旅企业类型的再划分与战略再定位(下篇)

    编者按:随着原国家旅游局和文化部合并成立新的文化和旅游部.国家自然资源部的组建,以及国家公园.国家文化公园的创建,国有旅游景区门票下降政策的普遍实施,叠加宏观经济下行.资本市场去杠杆以及新冠肺炎疫情的 ...

  • “智慧文旅”提升来滇旅客出行体验

    近日,云南腾云信息产业有限公司与云南祥鹏航空有限责任公司.飞享互联航空科技(海南)有限公司签署战略合作协议,将共同推进"航空互联网++智慧文旅"创新服务解决方案的试点与落地,提高旅 ...

  • 旅发大会召开在即——十景、三餐、两剧,您打卡了几个?

    5月7日上午,2021年全省旅游产业发展大会新闻发布会在南昌举行.根据省委.省政府工作部署,2021年全省旅游产业发展大会将于5月17日-19日在景德镇市举办. 本届旅发大会在千年古镇.世界瓷都举办, ...

  • 一起去打卡!上海市文旅局局长为这三条微游线路代言

    图说:上海"建筑可阅读"进入数字转型 采访对象供图(下同) 新民晚报讯(记者 杨玉红)"建筑可阅读"成为市民游客的休闲好去处,2019年,累计接待了1830万人 ...

  • 2128人参赛!千人走戈壁领跑中国文体旅产业复苏新节奏

    第7届千人走戈壁报名通道已经关闭,本届千人走戈壁共计9504人报名,136899人关注并提供支持,最终将有2128名徒友踏上第7届千人走戈壁的战场上,这些徒友来自全球20个国家的226座城市. 千人走 ...