1. 线程池整体概括:
创建线程还是比较简单的,但是由于线程的创建和销毁需要耗费一定的开销(默认情况下,主线程占用1M,子线程占用512KB,线程越多,占用内存也越多),过多的使用线程反而会造成内存资源的浪费,从而影响性能,出于对性能的考虑,于是引入了线程池的概念。
线程池并不是在CLR初始化的时候立刻创建的,而是在应用程序要创建线程来执行任务的时候,线程池才会初始化一个线程,初始化的线程和其他线程一样,但是在线程完成任务之后不会自行销毁,而是以挂起的状态回到线程池,当应用程序再次向线程池发出请求的时候,线程池里挂起的线程会再度激活执行任务。这样做可以减少线程创建和销毁所带来的开销。
简单说:线程池,其实就是一个容纳多个线程的容器,其中的线程可以反复使用,省去了频繁创建线程对象的操作,无需反复创建线程而消耗过多资源。线程池非常适合大量小的运算。当应用程序想要执行一个异步操作时,需要调用QueueUserWorkItem方法将对应的任务添加到线程池中。线程池会从队列中提取任务, 并且将其委派给线程池中的线程执行。
使用线程池的方法:
ThreadPool.QueueUserWorkItem(CallBackWorkItem); //CallBackWorkItem 参数为线程池线程执行的回调方法
ThreadPool.QueueUserWorkItem(CallBackWorkItem, "abc"); //CallBackWorkItem 参数为线程池线程执行的回调方法 第二个参数表示传递给回调方法的参数
void CallBackWorkItem(object state)
{
Console.WriteLine("子线程执行");
if(state != null){
Console.WriteLine("使用这行语句调用了这个线程方法 : ThreadPool.QueueUserWorkItem(CallBackWorkItem, "abc")");
}
else{
Console.WriteLine("使用这行语句调用了这个线程方法 : ThreadPool.QueueUserWorkItem(CallBackWorkItem)");
}
}
2. 线程池使用后性能提升例子:
测试下通过创建线程与利用线程池线程来做事所需时间及观察下利用线程池时是不是只用到少数几个线程。
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000; i++)
{
Thread thread = new Thread(() => {
int count = 0;
count++;
});
thread.Start();
//new Thread(() =>
//{
// int count = 0;
// count++;
//}).Start();
}
sw.Stop();
Console.WriteLine("运行创建线程所花费时间"+sw.ElapsedMilliseconds);
sw.Restart();//重置下计时器
for (int i = 0; i < 1000; i++)
{
//此处s为WaitCallback类型,转到定义查看为public delegate void WaitCallback(object state),即是有一个参数的无返回值的委托
ThreadPool.QueueUserWorkItem((s) =>
{
int count = 0;
Console.WriteLine(Thread.CurrentThread.ManagedThreadId);
count++;
});
}
sw.Stop();
Console.WriteLine("运行线程池线程所花费时间"+sw.ElapsedMilliseconds);
Console.ReadKey();
}
运行结果的部分截图如下:
可以看到通过创建线程循环的输出远远大于利用线程池里线程循环输出所需时间,线程池的效率很高,同时利用线程池的循环只用到了少数几个线程。
3. 深入理解线程池的例子:
class Program
{
static void Main(string[] args)
{
ThreadDemoClass demoClass = new ThreadDemoClass();//实例化类的对象
//使用委托绑定线程池要执行的方法(无参数)
WaitCallback waitCallback1 = demoClass.Run1;
//将方法排入队列,在线程池变为可用时执行
ThreadPool.QueueUserWorkItem(waitCallback1);
//使用委托绑定线程池要执行的方法(有参数)
WaitCallback waitCallback2 = new WaitCallback(demoClass.Run1);
//将方法排入队列,在线程池变为可用时执行
ThreadPool.QueueUserWorkItem(waitCallback2, "张三");
UserInfo userInfo = new UserInfo();
userInfo.Name = "李四";
userInfo.Age = 33;
//使用委托绑定线程池要执行的方法(有参数,自定义类型的参数)
WaitCallback waitCallback3 = new WaitCallback(demoClass.Run2);
//将方法排入队列,在线程池变为可用时执行
ThreadPool.QueueUserWorkItem(waitCallback3, userInfo);
Console.WriteLine();
Console.WriteLine("Main thread working...");
Console.WriteLine("Main thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString());
Console.ReadKey();
}
}
public class ThreadDemoClass
{
public void Run1(object obj)
{
string name = obj as string;
Console.WriteLine();
Console.WriteLine("Child thread working...");
Console.WriteLine("My name is " + name);
Console.WriteLine("Child thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString());
}
public void Run2(object obj)
{
UserInfo userInfo = (UserInfo)obj;
Console.WriteLine();
Console.WriteLine("Child thread working...");
Console.WriteLine("My name is " + userInfo.Name);
Console.WriteLine("I'm " + userInfo.Age + " years old this year");
Console.WriteLine("Child thread ID is:" + Thread.CurrentThread.ManagedThreadId.ToString());
}
}
public class UserInfo
{
public string Name { get; set; }
public int Age { get; set; }
}
运行结果:
本文根据徐照兴教授讲义编写,有些改动。