C#线程池已达最大容量为何仍接受并运行新任务?
问题描述
我在学习C#线程池时写了个示例,把线程池的MaxThreads设为2,同时提交4个任务,但运行后发现4个任务居然同时跑起来了。
我的代码:
static void Main(string[] args) { ThreadPoolExample_0(); while (true) { Thread.Sleep(2000); } } public static void ThreadPoolExample_0() { ThreadPool.SetMaxThreads(2,2); for (int i = 0; i < 4; i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(Task), i); } Console.ReadLine(); } static void Task(object state) { Console.WriteLine("Task {0} is running on a thread from the thread pool.", state); Thread.Sleep(1000); Console.WriteLine("Task {0} exited.", state); }
运行输出:
Task 3 is running on a thread from the thread pool.
Task 0 is running on a thread from the thread pool.
Task 1 is running on a thread from the thread pool.
Task 2 is running on a thread from the thread pool.
Task 0 exited.
Task 3 exited.
Task 1 exited.
Task 2 exited.
这到底是代码写错了,还是我对线程池的理解有问题?
问题分析与解决
问题出在你对ThreadPool.SetMaxThreads的使用和理解上:
SetMaxThreads调用大概率未生效
线程池有两个核心参数:MinThreads(线程池维护的最小工作线程数)和MaxThreads(线程池允许创建的最大工作线程数)。默认情况下,MinThreads的值等于CPU核心数(比如4核CPU就是4),而SetMaxThreads要求设置的最大值不能小于MinThreads,否则调用会直接失败(返回false,但你代码里没检查这个返回值)。所以你设置的MaxThreads(2,2)根本没生效,线程池还是用原来的默认最大值,自然能同时运行4个任务。要限制并发数,需同时设置
MinThreads和MaxThreads
如果想严格限制最多2个线程同时运行,需要先把MinThreads也设为2,再设置MaxThreads,这样线程池才会遵守这个限制。
修改后的代码:
public static void ThreadPoolExample_0() { // 先设置最小工作线程数为2 ThreadPool.SetMinThreads(2, 2); // 再设置最大工作线程数为2,此时会生效 bool setSuccess = ThreadPool.SetMaxThreads(2, 2); Console.WriteLine($"MaxThreads设置是否成功:{setSuccess}"); for (int i = 0; i < 4; i++) { ThreadPool.QueueUserWorkItem(new WaitCallback(Task), i); } Console.ReadLine(); }
- 线程池的调度逻辑
当你提交任务时,线程池会先快速创建线程,直到达到MinThreads的数量;之后如果队列里还有任务,线程池会优先等待现有线程空闲,只有当等待超过一定时间后,才会在MaxThreads的限制内创建新线程。所以当MinThreads和MaxThreads都设为2时,最多只会有2个任务同时运行,剩下的任务会排队等待空闲线程。
修改后的代码运行时,你会看到类似这样的输出(顺序可能有变化,但同一时间最多2个任务在运行):
Task 0 is running on a thread from the thread pool.
Task 1 is running on a thread from the thread pool.
Task 0 exited.
Task 2 is running on a thread from the thread pool.
Task 1 exited.
Task 3 is running on a thread from the thread pool.
Task 2 exited.
Task 3 exited.
内容的提问来源于stack exchange,提问作者Han Han

