2026/6/10 1:42:13
网站建设
项目流程
网站优化+山东,建网站能上传多少数据,梁山专业网站建设,免费的h5制作平台今天我们来详细介绍一下多线程#xff0c;多线程是.NET中非常重要的知识点#xff0c;需要完全掌握。
一、什么是多线程#xff1f;
在了解线程之前#xff0c;我们需要知道什么是进程#xff0c;所谓进程#xff0c;就是指操作系统中运行的程序#xff0c;比如我们自己…今天我们来详细介绍一下多线程多线程是.NET中非常重要的知识点需要完全掌握。一、什么是多线程在了解线程之前我们需要知道什么是进程所谓进程就是指操作系统中运行的程序比如我们自己写的在运行的.NET程序或者是正在运行的QQ、微信、浏览器等这些都叫做一个进程进程与进程之间保持独立比如浏览器崩了不会影响微信。如果操作系统是一个工厂那么进程就是一个车间而车间里的工人就是线程。如果一个进程里只有一个工人那就是单线程由于只有一个工人所以效率比较慢如果一个进程里有多个工人那就是多线程由于可以多个工人相互配合所以效率相对较高。二、什么是同步异步这里需要重点介绍一下同步异步的知识因为总有小伙伴会将同步异步和单线程多线程搞混。同步你自己点外卖拿着手机一直等等商家接单、等商家做、等骑手送期间你啥也干不了就傻坐着等这就是「线程阻塞」。 不管是 1 个人干单线程还是 2 个人干多线程只要你等事儿干完就是同步。异步你用 APP 点完外卖把手机一扔该刷剧刷剧、该打游戏打游戏等外卖到了手机响通知你再去拿 ——不等事儿干完先干别的。 这就是异步重点是「不傻等」和 “几个人干活” 没关系。三、单线程多线程与同步异步的区别同步 / 异步只看你「要不要等事儿干完」做事的方式单线程 / 多线程只看你「有几个人干活」干活的人。3.1 区分同步异步如何区分同步异步只要看当前运行的线程会不会等待方法执行结束比如我下面这两个例子namespaceConsoleTest{publicclassProgram{staticvoidMain(string[]args){{Console.WriteLine(同步点外卖);SyncOrder();}Console.WriteLine();{Console.WriteLine(异步点外卖);AsyncOrder();}}staticvoidSyncOrder(){Console.WriteLine(下单成功);Console.WriteLine(一直盯着手机等待骑手送达);Thread.Sleep(2000);Console.WriteLine(两秒钟后骑手送到);}staticvoidAsyncOrder(){Console.WriteLine(下单成功);ThreadthreadnewThread((){Console.WriteLine(让手机自己等待外面到了再提醒我);Thread.Sleep(2000);Console.WriteLine(手机提示外卖到了);});thread.Start();Console.WriteLine(我自己去洗碗了~~~~);}}}Thread.Sleep的作用是让当前正在执行的线程暂停休眠指定的毫秒数期间释放 CPU 资源让给其他线程干活休眠时间到了再继续执行。我们返回刚刚的概念如何区分同步异步只要看当前运行的线程会不会等待方法执行结束由于SyncOrder中我让当前运行的线程睡眠了2秒这个线程必须等待2秒2秒后才可以继续运行其他代码所以这里的SyncOrder是同步方法。不同的是当主线程开始执行AsyncOrder后AsyncOrder会在内部新创建一个线程这个新线程负责等待2秒但是需要注意的是主线程并不会等待新线程执行完毕当方法内部执行了thread.Start()后新线程开始执行等待方法而主线程继续往下走执行Console.WriteLine(我自己去洗碗了~~~~)这个洗碗操作所以这里是异步方法。执行结果同步点外卖 下单成功 一直盯着手机等待骑手送达 两秒钟后骑手送到异步点外卖 下单成功 我自己去洗碗了~~~~让手机自己等待外面到了再提醒我 手机提示外卖到了那这里的异步方法能不能也改成同步方法呢答案是可以的同步方法的核心不就是让主线程等待嘛那我们也只需要让主线程等待新线程执行不就把它变成同步方法了staticvoidAsyncOrder(){Console.WriteLine(下单成功);ThreadthreadnewThread((){Console.WriteLine(让手机自己等待外面到了再提醒我);Thread.Sleep(2000);Console.WriteLine(手机提示外卖到了);});thread.Start();// 让主线程等待新线程执行完毕thread.Join();Console.WriteLine(我自己去洗碗了~~~~);}我们这里只加了一行代码thread.Join()作用就是让主线程等待新线程执行完毕随后再去执行下面的洗碗方法这样改变后这个AsyncOrder也就变成了一个同步方法。修改后的结果同步点外卖 下单成功 一直盯着手机等待骑手送达 两秒钟后骑手送到异步点外卖 下单成功 让手机自己等待外面到了再提醒我 手机提示外卖到了 我自己去洗碗了~~~~原本下单成功就可以去洗碗现在要等待外卖到了再去洗碗可见AsyncOrder也变成了一个同步方法。虽然都是让主线程陷入等待但是两个同步方法实现的等待逻辑有所不同一开始的同步方法只有一个主线程主线程会等待是因为执行了Thread.Sleep方法相当于让它自己陷入了睡眠。后面由异步方法改造而成的同步方法主线程会等待是因为执行力thread.Join();这个方法导致主线程必须等待新线程执行完毕相当于必须等待别人完成任务你才可以开始。新手小伙伴一定要好好看这两个代码才能深入理解同步异步的区别3.2 区分单线程多线程相比之下区分单线程多线程就容易得多只要看代码是否运行在多个线程上。换句话说也就是看也没有创建新的线程并且启动新的线程。由于下面的代码中我并没有创建新的线程更没有调用所以这个代码在主线程上运行namespaceSingleMultiThreadDemo{classProgram{staticvoidMain(string[]args){// 单线程核心所有代码都在主线程线程ID固定Console.WriteLine($主线程代码 —— 线程ID{Thread.CurrentThread.ManagedThreadId});// 调用普通方法还是在主线程DoSomething();// 即使有循环/延时依然是同一个线程Thread.Sleep(1000);Console.WriteLine($延时后代码 —— 线程ID{Thread.CurrentThread.ManagedThreadId});}staticvoidDoSomething(){Console.WriteLine($普通方法代码 —— 线程ID{Thread.CurrentThread.ManagedThreadId});}}}调用结果主线程代码 —— 线程ID1 普通方法代码 —— 线程ID1 延时后代码 —— 线程ID1下面的代码中我创建了新的线程并且启动了新的线程所以这个代码在多个线程上运行namespaceSingleMultiThreadDemo{classProgram{staticvoidMain(string[]args){Console.WriteLine($主线程代码 —— 线程ID{Thread.CurrentThread.ManagedThreadId});// 多线程核心创建新线程新线程有独立IDThreadnewThreadnewThread((){Console.WriteLine($新线程代码 —— 线程ID{Thread.CurrentThread.ManagedThreadId});});newThread.Start();// 线程池/Task.Run也是多线程常用System.Threading.Tasks.Task.Run((){Console.WriteLine($线程池线程代码 —— 线程ID{Thread.CurrentThread.ManagedThreadId});});// 等一下避免程序提前退出Thread.Sleep(1000);}}}执行结果主线程代码 —— 线程ID1新线程代码 —— 线程ID7线程池线程代码 —— 线程ID6多线程这里需要注意的是如果创建了其他线程但是没有启动那么程序还是运行在主线程所以还是单线程的。3.3 异步与多线程需要重点注意的是异步不一定代表多线程多线程只是实现异步的其中一种方法单线程也可以实现异步只要保障不让程序处于等待状态就行了比如下面这个方法你不需要能每行代码都理解但是你需要理解异步不只可以由多线程实现这个思想。namespaceAsyncNotMultiThreadDemo{classProgram{staticasyncTaskMain(string[]args){Console.WriteLine( 单线程异步无多线程 );// 打印主线程ID全程唯一Console.WriteLine($当前线程ID{Thread.CurrentThread.ManagedThreadId});Console.WriteLine(1. 点击下载歌曲手机开始处理下载请求);// Task.Delay异步等待无新线程靠操作系统定时器vardownloadTaskTask.Delay(2000);// 模拟下载耗时2秒// 异步核心不等下载完成直接干别的刷歌单Console.WriteLine(2. 不等下载完成继续刷歌单异步);Console.WriteLine($当前线程ID{Thread.CurrentThread.ManagedThreadId});// 还是主线程// 等下载完成全程无新线程awaitdownloadTask;Console.WriteLine(3. 下载完成当前线程ID{Thread.CurrentThread.ManagedThreadId});}}}Task.Delay()与Thread.Sleep()不同Task.Delay靠操作系统定时器实现不阻塞当前线程所以能单线程异步等待Thread.Sleep()是只能单线程同步等待所以在这里使用Task.Delay()时主程序并不会停下来等待而是立即执行后面的代码当代码执行到await downloadTask;时才会等待计时结束。于是就实现了非多线程的异步。那我们能不能把这个方法改成同步呢namespaceAsyncNotMultiThreadDemo{classProgram{staticasyncTaskMain(string[]args){Console.WriteLine( 单线程异步无多线程 );// 打印主线程ID全程唯一Console.WriteLine($当前线程ID{Thread.CurrentThread.ManagedThreadId});Console.WriteLine(1. 点击下载歌曲手机开始处理下载请求);// Task.Delay异步等待无新线程靠操作系统定时器vardownloadTaskTask.Delay(2000);// 模拟下载耗时2秒// 等下载完成全程无新线程awaitdownloadTask;// 异步核心不等下载完成直接干别的刷歌单Console.WriteLine(2. 不等下载完成继续刷歌单异步);Console.WriteLine($当前线程ID{Thread.CurrentThread.ManagedThreadId});// 还是主线程Console.WriteLine(3. 下载完成当前线程ID{Thread.CurrentThread.ManagedThreadId});}}}当我们把await downloadTask;这个等待指令放到执行前面后主线程就无法往下执行代码而是会卡在这里于是这个就又变成了同步。然鹅我们实现异步最常用的还是多线程我们再举一个例子namespaceAsyncNotMultiThreadDemo{classProgram{staticvoidMain(string[]args){Console.WriteLine( 多线程异步 );Console.WriteLine($主线程ID{Thread.CurrentThread.ManagedThreadId});Console.WriteLine(1. 喊室友帮我下载歌曲);// 新建线程多线程实现异步ThreadnewThreadnewThread((){Console.WriteLine($室友线程ID{Thread.CurrentThread.ManagedThreadId});Thread.Sleep(2000);// 模拟下载2秒Console.WriteLine(2. 室友下载完成);});newThread.Start();// 异步核心不等室友自己刷歌单Console.WriteLine(3. 不等室友我继续刷歌单异步);Thread.Sleep(3000);// 等室友完成避免程序提前退出}}}这个代码中我们并不关心是由线程是什么时候结束的我们用Thread.Sleep(3000)在主线程等待了一个很长的时间来确保它一定可以结束。多线程异步主线程ID11.喊室友帮我下载歌曲3.不等室友我继续刷歌单异步 室友线程ID72.室友下载完成但是如果规定了室友线程什么时候结束呢namespaceAsyncNotMultiThreadDemo{classProgram{staticvoidMain(string[]args){Console.WriteLine( 多线程同步 );Console.WriteLine($主线程ID{Thread.CurrentThread.ManagedThreadId});Console.WriteLine(1. 喊室友帮我下载歌曲);// 新建线程多线程实现异步ThreadnewThreadnewThread((){Console.WriteLine($室友线程ID{Thread.CurrentThread.ManagedThreadId});Thread.Sleep(2000);// 模拟下载2秒Console.WriteLine(2. 室友下载完成);});newThread.Start();newThread.Join();// 异步核心不等室友自己刷歌单Console.WriteLine(3. 等室友室友执行结束我才可以刷歌单同步);}}}现在我只是在调用新的线程后加了一行代码newThread.Join()这个代码告诉主线程你必须在这里等待室友线程执行结束你才可以继续往下执行于是就变成了同步这里的同步不是单线程同步而是主线程同步等待其他线程执行完成。执行结果多线程同步主线程ID11.喊室友帮我下载歌曲 室友线程ID72.室友下载完成3.等室友室友执行结束我才可以刷歌单同步总结不管是何种类型的同步异步我们只要关心主线程是否会等待换句话说我们只要关心主线程是否会阻塞。不管是何种类型的单线程多线程我们只要关心程序是运行在几个线程上的即有没有创建新的线程并且启动新的线程。