许多应用程序使用多个线程,但这些线程经常在休眠状态中耗费大量的时间来等待事件发生。其他线程可能进入休眠状态,并且仅定期被唤醒以轮询更改或更新状态信息,然后再次进入休眠状态。为了简化对这些线程的管理,.NET框架为每一个进程提供了一个线程池,使应用程序能够根据需要来有效地利用多个线程。一个线程监视排到线程池的若干个等待操作的状态。当一个等待操作完成时,线程池中的一个辅助线程就会执行对应的回调函数。线程池中的线程由系统进行管理,程序员不需要费力于线程管理,可以集中精力处理应用程序任务。

线程池是一种多线程处理形式,处理过程中将任务添加到队列,然后在创建线程后自动启动这些任务。线程池线程都是后台线程。每个线程都使用默认堆栈大小,以默认的优先级运行,并处于多线程单元中。如果某个线程在托管代码中空闲(如正在等待某个事件),则线程池将插入另一个辅助线程来使所有处理器保持繁忙。如果所有线程池线程都始终保持繁忙,但队列中包含挂起的工作,则线程池将在一段时间之后创建另一个辅助线程。但线程的数目永远不会超过最大值。超过最大值的其他线程可以排队,但它们要等到其他线程完成后才启动。

线程池特别适合于执行一些需要多个线程的任务。使用线程池能够优化这些任务的执行过程,从而提高吞吐量,它不仅能够使系统针对此进程优化该执行过程,而且还能够使系统针对计算机上的其他进程优化该执行过程。如果需要启动多个不同的任务,而不想分别设置每个线程的属性,则可以使用线程池。

如果应用程序需要对线程进行特定的控制,则不适合使用线程池,需要创建并管理自己的线程。不适合使用线程池的情形包括:

— 如果需要使一个任务具有特定的优先级。

— 如果具有可能会长时间运行(并因此阻塞其他任务)的任务。

— 如果需要将线程放置到单线程单元中(线程池中的线程均处于多线程单元中)。

— 如果需要用永久标识来标识和控制线程,比如想使用专用线程来中止该线程,将其挂起或按名称发现它。

System.Threading.ThreadPool类实现了线程池。ThreadPool类是一个静态类,它提供了管理线程池的一系列方法。

ThreadPool.QueueUserWorkItem方法在线程池中创建一个线程池线程来执行指定的方法(用委托WaitCallback来表示),并将该线程排入线程池的队列等待执行。QueueUserWorkItem方法的原型为:

public static Boolean QueueUserWorkItem(WaitCallback wc, Object state);

public static Boolean QueueUserWorkItem(WaitCallback wc);
这些方法将“工作项”(和可选状态数据)排列到线程池的线程中,并立即返回。工作项只是一种方法(由wc参数标识),它被调用并传递给单个参数,即状态(状态数据)。没有状态参数的QueueUserWorkItem版本将null传递给回调方法。线程池中的某些线程将调用System.Threading.WaitCallback委托表示的回调方法来处理该工作项。回调方法必须与System.Threading.WaitCallback委托类型相匹配。WaitCallback定义如下:

public delegate void WaitCallback(Object state);

调用QueueUserWorkItem时传入的Object类型参数将传递到任务过程,可以通过这种方式来向任务过程传递参数。如果任务过程需要多个参数,可以定义包含这些数据的类,并将类的实例强制转换为Object数据类型。

每个进程都有且只有一个线程池。当进程启动时,线程池并不会自动创建。当第一次将回调方法排入队列(比如调用ThreadPool.QueueUserWorkItem方法)时才会创建线程池。一个线程监视所有已排队到线程池中的任务。当某项任务完成后,线程池中的线程将执行相应的回调方法。在对一个工作项进行排队之后将无法取消它。

线程池中的线程数目仅受可用内存的限制。但是,线程池将对允许在进程中同时处于活动状态的线程数目强制实施限制(这取决于CPU的数目和其他因素)。默认情况下,每个系统处理器最多可以运行25个线程池线程。通过使用ThreadPool.GetMaxThreads和ThreadPool.SetMax
Threads方法,可以获取和设置线程池的最大线程数。

即使是在所有线程都处于空闲状态时,线程池也会维持最小的可用线程数,以便队列任务可以立即启动。将终止超过此最小数目的空闲线程,以节省系统资源。默认情况下,每个处理器维持一个空闲线程。使用ThreadPool.GetMinThreads和ThreadPool.SetMinThreads方法可以获取和设置线程池所维持的空闲线程数。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading; namespace ThreadPoolApp
{
    class Program
    {
        static void Main(string[] args)
        {
            int maxThreadNum, portThreadNum, minThreadNum;            
            Console.WriteLine("Main thread start:");
            ThreadPool.GetMaxThreads(out maxThreadNum, out portThreadNum);
            ThreadPool.GetMinThreads(out minThreadNum, out portThreadNum);
            Console.WriteLine("The max thread num is {0}", maxThreadNum);
            Console.WriteLine("The mix thread num is {0}", minThreadNum);             for(int i=1; i<=8; i++)
            {
                ThreadPool.QueueUserWorkItem(Getvalue, i);
                //Thread.Sleep(2000);
                //ThreadPool.QueueUserWorkItem(Setvalue, i);
            }
            Console.WriteLine("Main thread: Doing other work here...");
            Thread.Sleep(2000);             ThreadPool.QueueUserWorkItem(Setvalue, 99999);             Console.WriteLine("Hit <Enter> Key to end this program.");
            Console.ReadLine();
        }
        private static void Getvalue(object sta)
        {
            Console.WriteLine("This is the {0} time to use this method.", sta);
            Thread.Sleep(1000);
        }
        private static void Setvalue(object sta)
        {
            Console.WriteLine("Hello Hello {0}.", sta);
            Thread.Sleep(1000);
        }
    }
}

//运行结果

Main thread start:
The max thread num is 500
The mix thread num is 2
Main thread: Doing other work here...
This is the 1 time to use this method.
This is the 2 time to use this method.
This is the 3 time to use this method.
This is the 4 time to use this method.
This is the 5 time to use this method.
This is the 6 time to use this method.
Hit <Enter> Key to end this program.
This is the 7 time to use this method.
This is the 8 time to use this method.
Hello Hello 99999.

C# 线程池异步调用的更多相关文章

  1. BeginInvoke 方法真的是新开一个线程进行异步调用吗?

    转自原文BeginInvoke 方法真的是新开一个线程进行异步调用吗? BeginInvoke 方法真的是新开一个线程进行异步调用吗? 参考以下代码: public delegate void tre ...

  2. java future模式 所线程实现异步调用(转载

    java future模式 所线程实现异步调用(转载) 在多线程交互的中2,经常有一个线程需要得到另个一线程的计算结果,我们常用的是Future异步模式来加以解决.Future顾名思意,有点像期货市场 ...

  3. 线程池 异步I/O线程 <第三篇>

    在学习异步之前先来说说异步的好处,例如对于不需要CPU参数的输入输出操作,可以将实际的处理步骤分为以下三步: 启动处理: 实际的处理,此时不需要CPU参数: 任务完成后的处理: 以上步骤如果仅仅使用一 ...

  4. Android AsyncTask内部线程池异步执行任务机制简要分析

    如下分析针对的API 25的AsyncTask的源码: 使用AsyncTask如果是调用execute方法则是同步执行任务,想要异步执行任务可以直接调用executeOnExecutor方法,多数情况 ...

  5. 转载 线程池 异步I/O线程 <第三篇>

    在学习异步之前先来说说异步的好处,例如对于不需要CPU参数的输入输出操作,可以将实际的处理步骤分为以下三步: 启动处理: 实际的处理,此时不需要CPU参数: 任务完成后的处理: 以上步骤如果仅仅使用一 ...

  6. 高并发场景-请求合并(二)揭秘HystrixCollapser-利用Queue和线程池异步实现

    背景 在互联网的高并发场景下,请求会非常多,但是数据库连接池比较少,或者说需要减少CPU压力,减少处理逻辑的,需要把单个查询,用某些手段,改为批量查询多个后返回. 如:支付宝中,查询"个人信 ...

  7. ThreadPool.QueueUserWorkItem引发的血案,线程池异步非正确姿势导致程序闪退的问题

    ThreadPool是.net System.Threading命名空间下的线程池对象.使用QueueUserWorkItem实现对异步委托的先进先出有序的回调.如果在回调的方法里面发生异常则应用程序 ...

  8. Java ExecutorServic线程池(异步)

    相信大家都在项目中遇到过这样的情况,前台需要快速的显示,后台还需要做一个很大的逻辑.比如:前台点击数据导入按钮,按钮后的服务端执行逻辑A,和逻辑B(执行大量的表数据之间的copy功能),而这时前台不能 ...

  9. java 线程池——异步任务

    一.简单粗暴的线程 最原始的方式,当我们要并行的或者异步的执行一个任务的时候,我们会直接使用启动一个线程的方式,如下面所示: new Thread(new Runnable() { @Override ...

随机推荐

  1. mysql死锁——mysql之四

    1.MySQL常用存储引擎的锁机制 MyISAM和MEMORY采用表级锁(table-level locking) BDB采用页面锁(page-level locking)或表级锁,默认为页面锁 In ...

  2. 在eclipse中首次新建项目的时候,出现Project interpreter not specified

    在eclipse中首次新建项目的时候,出现Project interpreter not specified(大致可以理解为:没有执行的项目编译者) 原因就是安装了pydev之后,我们的python还 ...

  3. SD/MMC卡初始化及读写流程

    二.MMC/SD卡的模型和工作原理 PIN脚.SD卡总线.SD卡结构.SD卡寄存器.上电过程 SD卡寄存器:  OCR:操作电压寄存器: 只读,32位 第31位: 表示卡上电的状态位   CID: 卡 ...

  4. jQuery插件之validate

    一.jQuery.validate.js插件用于对表单输入进行验证,其使用配置非常简单.支持多事件触发,自带多种验证规则,还支持自定义验证规则. 1.配置方法. 先导入jQuery库,然后导入Vali ...

  5. jQuery中append html后绑定事件不起作用

    事件一定要紧跟append之后, 否则append元素点击不起作用 $(function(){$('div').append('<ul><li id="appli" ...

  6. vector迭代器失效的一种情形

    使用过STL的人都应该知道关于迭代器失效的原理,这里以后vector迭代器失效为例: 第一种:当插入一个元素到vector中,如果插入后容器已满,那么容器将新开辟一块内存区域,然后 将原内存中的数据拷 ...

  7. Cocos2d-x 架构一个游戏的一般思路

    采用下面的步骤来实现游戏逻辑: 通过应用程序代理类来初始化第一个CCScene(即AppDelegate里面的第一个CCScene), CCScene里面实例化一个或者多个CCLayer,并把它们当作 ...

  8. JNI的替代者—使用JNA访问Java外部功能接口

    摘自:http://www.cnblogs.com/lanxuezaipiao/p/3635556.html JNI的替代者-使用JNA访问Java外部功能接口 1. JNA简单介绍 先说JNI(Ja ...

  9. ALSA音频工具amixer,aplay,arecord

    ALSA音频工具编译安装 ========================================================================1.官网http://www. ...

  10. onvif规范的实现:server端Discovery实现,通过OnvifTestTool12.06测试

    说明:网上关于ONVIF开发的文章并不多,也更找不到具体的实例来入门学习.只能靠翻阅各种Specification摸索中前进,下面是最近几天的成果.调通了服务端(或者说设备端)的Discovery,使 ...