4. 线程池
4.1 简介
一般情况下我们都使用Thread类创建线程,因为通过Thread对象可以对线程进行灵活的控制。但创建线程和销毁线程代价不菲,过多的线程会消耗掉大量的内存和CPU资源,假如某段时间内突然爆发了100个短小的线程,创建和销毁这些线程就会消耗很多时间,可能比线程本身运行的时间还长。为了改善这种状况,.NET提供了一种称之为线程池Thread Pool)的技术。线程池提供若干个固定线程轮流为大量的任务服务,比如用10个线程轮流执行100个任务,当一个线程完成任务时,并不马上销毁,而是接手另一个任务,从而减少创建和销毁线程的消耗。
ThreadPool是一个静态类,不必创建实例就可以使用它。一个应用程序最多只有一个线程池,它会在首次向线程池中排入工作函数时自动创建。
class Program
{
public static voidThreadPoolTest()
{
//向线程池中添加100个工作线程
for(inti = 1; i <= 100; i++)
{
ThreadPool.QueueUserWorkItem(new WaitCallback(WorkFunction), i);
}
}
//工作函数
public static voidWorkFunction(objectn)
{
Console.Write(n + "\t");
}
static voidMain(string[] args)
{
ThreadPoolTest();
Console.ReadKey(); //按下任意键结束程序
}
}
在上面的程序中,我们向线程池中排入了100个工作函数,线程池分别独立的完成了这100个任务。通过这个简单的例子,我们学会了线程池的使用方式,下面我们研究一下线程池运行过程中线程数目的变化情况,从而加深对线程池的理解。为了叙述方便,我们假设下限为10,上限为30。
1.当线程池被创建后,里面就会创建10个空线程(和下限值相同)。
2.当我们向线程池中排入一个任务后,就会有一个空线程接手该任务,然后运行起来。随着我们不断向线程池中排入任务,线程池中的空线程逐一运行起来。
3.随着任务的不断增加,在某一时刻任务数量会超出下限,这时线程的数量就不够用了,但线程池并不会立即创建新线程,而是等待500毫秒左右,这么做的目的是看看在这段时间内是否有其他线程完成任务并接手这个请求,这样就可以避免因创建新线程而造成的消耗。如果这段时间内没有线程完成任务,就创建一个新线程去执行新任务。
4.在任务数量超过下限后,随着新任务的不断排入,线程池中线程数量持续增加,直至达到上限值为止。
5.当线程数量达到上限时,继续增加任务,线程数量将不再增加。比如你向线程池中排入100个任务,则只有30个进入线程池(和上限相同),另外70个在线程池外排队等待。当线程池中的某个线程完成任务后,并不会立即终止,而是从等待队列中选择一个任务继续执行,这样就减少了因创建和销毁线程而消耗的时间。
6.随着任务逐步完成,线程池外部等候的任务被逐步调入线程池,任务的数量逐步减少,但线程的总数保持恒定,始终为30(和上限值相同)。
7&