摘要:
系列文章,从一个基本的代码说起,逐步探索 ThreadPool 的奥妙。
首先,看看线程池的样子:

从上图看出,线程池维护1个至n个线程,操作系统从请求队列中提取请求分配个线程池中的适合线程处理。
先写下如下的代码:
using System;
using System.Threading;

public class ThreadBase


{

public static void Main ( )
{

System.Threading.WaitCallback waitCallback = new WaitCallback ( MyThreadWork );

ThreadPool.QueueUserWorkItem ( waitCallback, "第一个线程" );
ThreadPool.QueueUserWorkItem ( waitCallback, "第二个线程" );
ThreadPool.QueueUserWorkItem ( waitCallback, "第三个线程" );
ThreadPool.QueueUserWorkItem ( waitCallback, "第四个线程" );
Console.ReadLine ( );
}


public static void MyThreadWork ( object state )
{
Console.WriteLine ( "线程现在开始启动…… {0}",(string)state );
Thread.Sleep ( 10000 );
Console.WriteLine ( "运行结束…… {0}",( string ) state );
}
}
分析上面的代码:
一、首先定义了一个 System.Threading.WaitCallback 对象 waitCallback。
WaitCallback 是一个委托,表示线程池线程要执行的回调方法,它的原型如下:
[ComVisibleAttribute(true)]
public delegate void WaitCallback (
Object state
)

1、这里有一个 Callback 机制的问题,所谓的Callback
简单的理解就是由操作系统调用的函数,我们自己写的程序不需要调用。就像有个修理工到家里搞修理,你只需要告诉他钳子、螺丝刀、胶布等修理工具在什么地方
就行,而不要管他在什么时候、在什么地方怎样使用这些修理工具。
2、WaitCallback 的参数" Object state",这个参数包含回调方法要使用的信息的对象。在接下来的情况中我再说。
既然 WaitCallback 委托的原型如此,那么我们就申明一个跟它的样子差不多的函数,这个函数就是要线程做的事情。
public static void MyThreadWork ( object state )
这里函数中多了一个 "static",这是因为Main的关系(更大一点就是因为C#语言机制的问题),如果WaitCallback 的对象不是在静态(static)方法中,这个static 是不需要的。
二、接着就是要执行的方法放入线程池中,以便操作系统执行。
我这里放置了四个方法要操作系统执行:
ThreadPool.QueueUserWorkItem ( waitCallback, "第一个线程" );
ThreadPool.QueueUserWorkItem ( waitCallback, "第二个线程" );
ThreadPool.QueueUserWorkItem ( waitCallback, "第三个线程" );
ThreadPool.QueueUserWorkItem ( waitCallback, "第四个线程" );
这里,我放置到线程池中的操作是一样的,当然也可以不一样,接下来说。
三、最后阻塞主线程,等待线程池中的线程执行
Console.ReadLine ( );
如果忽略掉这个代码,则有可能看不到任何输出
好了,这是主线程做的事情了,接下来看看线程池中的线程做的事情。
这个很简单,就是将线程的参数输出,然后线程睡眠(sleep)一段时间,最后输出线程结束的信息。
-------------------------------------------------------------------------------------------------------------------------------------------------
好的,第一个问题,因为 WaitCallback 委托的原型决定了参数只能有一个 ( Object state ),那没有办法,我们只能将多个参数封装到一个Object 中,也就是 class 中。
第二个问题,要处理这个问题也很简单,就是再定义一个 WaitCallback 委托的对象,将它作为参数传递给ThreadPool.QueueUserWorkItem ()方法。这个对象可以在线程里面处理另外一类的工作。
代码如下:
using System;
using System.Threading;

public class App


{

public static void Main ( )
{
WaitCallback waitCallback = new WaitCallback ( MyThreadWork );

WaitCallback waitCallback2= new WaitCallback ( MyThreadWork2 ); // 增加线程工作类型

ThreadPool.QueueUserWorkItem ( waitCallback, "第一个线程" );
ThreadPool.QueueUserWorkItem ( waitCallback, "第二个线程" );

MyState myState = new MyState ( "第三个线程",100); // 增加自定义的线程参数类型
ThreadPool.QueueUserWorkItem ( waitCallback2, myState );
ThreadPool.QueueUserWorkItem ( waitCallback2, new MyState("第四个线程",2) );

Console.WriteLine ( "MyState 的 Number 值为: {0}", myState.Number ); // 读取线程改变后的 MyState
Console.ReadLine ( );
}


public static void MyThreadWork ( object state )
{
Console.WriteLine ( "MyThreadWork 开始启动 …… {0}", ( string ) state );
Thread.Sleep ( 10000 );
Console.WriteLine ( "运行结束…… {0}", ( string ) state );
}

// use MyState class

public static void MyThreadWork2 ( object state )
{
Console.WriteLine ( "MyThreadWork2 开始启动…… {0},{1}", ( ( MyState ) state ).Info, ( ( MyState ) state ).Number );
Thread.Sleep ( 10000 );
( ( MyState ) state ).Number += 1; // 将 state的 Number 加 1
Console.WriteLine ( "运行结束…… {0},{1}", ( ( MyState ) state ).Info, ( ( MyState ) state ).Number );
}
}

public class MyState


{
private string info;
private int number;



public MyState ( string info, int number )
{
this.info = info;
this.number = number;
}


public string Info
{

get
{
return this.info;
}

set
{
this.info = value;
}
}


public int Number
{

get
{
return this.number;
}

set
{
this.number = value;
}
}
}
在代码里面,我尝试对三个问题都进行解决,但是,很遗憾,上面的代码只是解决了第1、2个问题。
虽然,我的MyThreadWork2 () 线程尝试对 MyState 的 Number 进行加1操作,但是,主线程的输出仍然可能是 100,如下所示:
MyState 的 Number 值为: 100
MyThreadWork 开始启动 …… 第一个线程
MyThreadWork 开始启动 …… 第二个线程
MyThreadWork2 开始启动…… 第三个线程,100
MyThreadWork2 开始启动…… 第四个线程,2
运行结束…… 第一个线程
运行结束…… 第二个线程
运行结束…… 第三个线程,101
运行结束…… 第四个线程,3
光从代码看,我们的输出 MyState 信息的代码应该是后面执行,想不到它居然在线程启动之前就执行了!
呵呵,这就是多线程!
看样子,我需要控制我的主线程——等所有的线程池中的线程都执行完成后,才接着执行主线程中输出 MyState 信息的代码。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧