使用Thread类已经可以创建并启动线程了,但是随着开启的线程越来越多,线程的创建和终止都需要手动操作,非常繁琐,另一个问题是,开启更多新的线程但是没有用的线程没有及时得到终止的时候,会占用越来越多的系统资源,影响性能。
所以,.net为我们引入了ThreadPool(线程池),我们只需要把要执行的任务放到线程池中即可,线程的开启包括资源的释放都由线程池帮我们完成。下面看一下怎么使用线程池。
核心类:System.Threading.ThreadPool, 线程池受.Net CLR管理的,每一个CLR都有一个线程池实例。
每个进程都有一个线程池,线程池的默认大小为:每个可用的处理器有 25 个线程。使用 SetMaxThreads 方法可以更改线程池中的线程数。每个线程使用默认的堆栈大小并按照默认的优先级运行。
ThreadPool类型拥有一个QueueUserWorkItem的静态方法。该静态方法接收一个委托,代表用户自定义的一个异步操作。在改方法被调用后,委托会进入到内部队列中。如果线程池中没有任何线程,将创建一个新的工作者线程(worker thread)并将队列中的第一个委托放入到该工作者线程中。
如果向线程池中放入新的操作,当之前的所有操作完成后,很可能只需重用一个线程来执行这些新的操作。如果QueueUserWorkItem执行的频率过快,线程池将创建更多的线程来执行这些新放入的异步委托。
线程池中的线程数是有限的,如果没有空闲的线程来执行这些异步委托操作,这种情况下,新的异步委托操作将在线程池的内部队列中等待,直到线程池中年的工作者线程空闲(有能力)来执行。
当停止向线程池中放入新的异步委托操作时,线程池会删除一定事件后过期的不在使用的线程,同时释放不再使用的系统资源。
线程池的使用非常简单,如下代码:
namespace ConsoleApplication18 { class Program { static void Main(string[] args) { Console.WriteLine("Main thread starting..."); //1,不带参数 ThreadPool.QueueUserWorkItem(AsyncAction); Thread.Sleep(TimeSpan.FromMilliseconds(3000)); //2,带参数 ThreadPool.QueueUserWorkItem(AsyncAction, "Async state"); Thread.Sleep(TimeSpan.FromMilliseconds(3000)); //3,lambda表达式 ThreadPool.QueueUserWorkItem(item => { Console.WriteLine("Sub thread starting..."); Console.WriteLine("Action state:" + item ?? string.Empty); Console.WriteLine(string.Format("Current thread id:{0}", Thread.CurrentThread.ManagedThreadId)); }, "Lambda state"); Thread.Sleep(TimeSpan.FromMilliseconds(3000)); Console.WriteLine("Main thread completed!"); Console.ReadKey(); } /// <summary> /// 委托匹配方法 /// </summary> /// <param name="obj"></param> static void AsyncAction(Object obj) { Console.WriteLine("Sub thread starting..."); Console.WriteLine("Action state:" + obj ?? string.Empty); Console.WriteLine(string.Format("Current thread id:{0}", Thread.CurrentThread.ManagedThreadId)); } } }
输出结果:
使用线程池创建线程这么简单,然后性能又好,是不是以后创建线程都去使用线程池呢?答案是否定的。
那么,以下场景是不适合使用线程池,而是自己创建并管理线程: