zoukankan      html  css  js  c++  java
  • 多线程(3)ThreadPool

      使用Thread类已经可以创建并启动线程了,但是随着开启的线程越来越多,线程的创建和终止都需要手动操作,非常繁琐,另一个问题是,开启更多新的线程但是没有用的线程没有及时得到终止的时候,会占用越来越多的系统资源,影响性能。

    所以,.net为我们引入了ThreadPool(线程池),我们只需要把要执行的任务放到线程池中即可,线程的开启包括资源的释放都由线程池帮我们完成。下面看一下怎么使用线程池。

    线程池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));
            }
    
        }
    }

    输出结果:

    不适合使用线程池的场景

     使用线程池创建线程这么简单,然后性能又好,是不是以后创建线程都去使用线程池呢?答案是否定的。

    那么,以下场景是不适合使用线程池,而是自己创建并管理线程:

    1. 需要前台线程时。因为线程池默认创建的都是后台线程。
    2. 需要线程具有特定的优先级。因为放到线程池中的线程都是由线程池来调度的,无法对其优先级进行设置。
    3. 需要长时间运行的任务。由于线程池具有最大线程数限制,因此大量阻塞的线程池线程可能会阻止任务启动。
  • 相关阅读:
    C# Note23: 如何自定义类型使用foreach循环
    C# Note22: 《Effective C#》笔记
    C# Note21: 扩展方法(Extension Method)及其应用
    C# Note20: 制作延时改变显示的标题栏
    C# Note19: Windows安装包制作实践
    Python Note1: Pycharm的安装与使用
    java Html&JavaScript面试题:HTML 的 form 提交之前如何验证数值文本框的内容全部为数字? 否则的话提示用户并终止提交?
    java Html&JavaScript面试题:用table显示n条记录,每3行换一次颜色,即1,2,3用红色字体,4,5,6用绿色字体,7,8,9用红颜色字体。
    java Html&JavaScript面试题:判断第二个日期比第一个日期大
    java算法面试题:金额转换,阿拉伯数字的金额转换成中国传统的形式如:(¥1011)->(一千零一拾一元整)输出。
  • 原文地址:https://www.cnblogs.com/mcgrady/p/7055171.html
Copyright © 2011-2022 走看看