多线程之旅(ThreadPool 线程池)
一、什么是ThreadPool 线程池(源码)
1.线程池顾名思义,有我们的系统创建一个容器装载着我们的线程,由CLR控制的所有AppDomain共享。线程池可用于执行任务、发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。所以使用线程池不需要自己创建线程,而是通过线程池来创建和执行和管理线程。
二、ThreadPool 线程池和线程的区别
1.ThreadPool 线程池是在.NET 2.0出现的,是一个享元模式整个程序共同享用这一个线程池,当我们的线程执行任务之后它不会立刻销毁,它会回到线程池中,如果有新的任务它就会去执行。避免了我们线程的重复创建和销毁(也不会造成我们CPU的上下文切换的损耗)。
2.大家仔细看一下我前面写的Thread 创建线程执行任务之后,它会自动销毁。那问题来了我们经常的创建、销毁线程这可都是资源的浪费呀!!所以我们要利用每个线程占有的资源。
三、ThreadPool 线程池缺点
1.线程池在性能上优于线程,但是它也是有缺点的。它不支持线程的取消、完成、失败通知等交互性操作。
2.它不能设置池中线程的Name,会增加使用者的难度。
3.线程池中线程通常都是后台线程,优先级为ThreadPriority.Normal
4.线程池堵塞会影响我们的性能,阻塞会使CLR错误地认为它占用了大量CPU。CLR能够检测或补偿(往池中注入更多线程),但是这可能使线程池受到后续超负荷的印象。Task (也及时后面要讲的)解决了这个问题。
5.线程池使用的是全局队列,全局队列中的线程依旧会存在竞争共享资源的情况,从而影响性能(Task 解决了这个问题,方案是使用本地队列)。
四、线程池工作原理
1.CLR初始化时,线程池中是没有线程的,但是内部有一个操作请求队列,当我们的应用程序使用异步时,会将一个记录项添加到线程池的队列中,线程池队列会自动读取这个记录项,并且发给一个线程池的线程,如果线程池没有线程就会创建一个线程执行这任务,当线程完成任务它不会自动销毁而是回到我们的线程池中,等待线程池派发新的任务。
2.如果程序给线程池派发了很多任务,线程池也会使用这一个线程执行所有的任务,如果我们的请求速度大于了我们的线程处理速度,就会创建额外线程,就不会导致我们创建了过多的线程。
2.当我们的线程有大量休息的,它们会在一段时间内自动销毁。这样很好的控制了我们应用程序的性能。
五、ThreadPool 线程池使用
1.ThreadPool是一个静态类,调用QueueUserWorkItem方法,是可以将一个异步计算放入我们的线程池队列中。
public static bool QueueUserWorkItem(WaitCallback callBack); public static bool QueueUserWorkItem(WaitCallback callBack, object state);
方法 | 说明 |
QueueUserWorkItem | 启动线程池里的一个线程(工作者线程) |
GetMinThreads | 检索线程池在新请求预测中能够按需创建的线程的最小数量。 |
GetMaxThreads | 最多可用线程数,所有大于此数目的请求将保持排队状态,直到线程池线程由空闲。 |
GetAvailableThreads | 剩余空闲线程数。 |
SetMaxThreads | 设置线程池中的最大线程数(请求数超过此值则进入队列)。 |
SetMinThreads | 设置线程池最少需要保留的线程数。 |
2.我们可以看到ThreadPool比Thread少了很多的API,被砍掉了

/// <summary> /// ThreadPool的使用 /// workerThreads CLR线程池分为工作者线程(workerThreads) /// completionPortThreads I/O线程(completionPortThreads) /// </summary> public static void Show() { //使用线程 ThreadPool.QueueUserWorkItem((x) => Running()); ThreadPool.GetAvailableThreads(out int workerThreads, out int completionPortThreads); Console.WriteLine($"没有设置线程数之前 workerThreads:{workerThreads} completionPortThreads:{completionPortThreads}"); //设置最大的线程数 ThreadPool.SetMaxThreads(16, 16); //设置最小的线程数 ThreadPool.SetMinThreads(8, 8); ThreadPool.GetAvailableThreads(out int workerThreads1, out int completionPortThreads1); Console.WriteLine($"设置最大的线程数之后 workerThreads:{workerThreads1} completionPortThreads:{completionPortThreads1}"); Console.ReadLine(); }
3.我们要注意的就是堵塞线程的时候一定要做好处理,最好是不要堵塞我们的线程,不然很容易造成死锁GG

/// <summary> /// ThreadPool 线程等待 ///类 包含了一个bool属性 ///false--WaitOne等待--Set--true--WaitOne直接过去 ///true--WaitOne直接过去--ReSet--false--WaitOne等待 ///https://www.cnblogs.com/howtrace/p/11362284.html /// </summary> public static void Show1() { //设置最大的线程数 ThreadPool.SetMaxThreads(16, 16); //设置最小的线程数 ThreadPool.SetMinThreads(8, 8); //设置false使用WaitOne()会直接堵塞线程,不会释放 、Set()设置为true ManualResetEvent manualResetEvent = new ManualResetEvent(false); //设置false使用WaitOne()会直接堵塞线程,不会释放 、Set()设置为true AutoResetEvent autoResetEvent = new AutoResetEvent(false); //上面两种方法都是可以拦截线程,都是继承EventWaitHandle 接口 //就都具有Reset() //红灯 设置为false导致线程等待 //Set() //绿灯 设置为true 启动线程继续执行 //WaitOne() // 等待信号 会根据我们线程状态执行,为true不需要等待直接执行 //反之为false会等待线程状态为true才会执行 //不同点 ManualResetEvent AutoResetEvent //ManualResetEvent 在·使用Set()的时候会所有处理 WaitOne 状态线程均继续执行。 //AutoResetEvent 在使用Set()的时候会执行一个线程其他的线程继续等待执行。 for (int i = 0; i < 20; i++) { var k = i; ThreadPool.QueueUserWorkItem(x => { Console.WriteLine(k); if (k < 18) { //等待线程,但是上面我们只开了16个线程,结果我18个线程全部等待 //导致了死锁 manualResetEvent.WaitOne(); } else { //恢复执行状态 manualResetEvent.Set(); } }); if (manualResetEvent.WaitOne()) { Console.WriteLine("没有死锁、、、"); } Console.WriteLine("等着QueueUserWorkItem完成后才执行"); } Console.ReadLine(); }
作者:匿名
出处:https://www.cnblogs.com/chenxi001/p/12601713.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架