1  线程池的概念

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

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

2  线程池的应用范围

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

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

在以下几种情况下,适合于使用线程池线程:

(1)不需要前台执行的线程。

(2)不需要在使用线程具有特定的优先级。

(3)线程的执行时间不易过长,否则会使线程阻塞。由于线程池具有最大线程数限制,因此大量阻塞的线程池线程可能会阻止任务启动。

(4)不需要将线程放入单线程单元。所有 ThreadPool 线程均不处于多线程单元中。

(5)不需要具有与线程关联的稳定标识,或使某一线程专用于某一任务。

3  ThreadPool类

在多线程的程序中,经常会出现两种情况:一种是在应用程序中,线程把大部分的时间花费在等待状态,等待某个事件发生,然后才能给予响应,这一般使用ThreadPool(线程池)来解决;另一种情况是在线程平时都处于休眠状态,只是周期性地被唤醒,这一般使用Timer(定时器)来解决。下面对ThreadPool类进行详细说明。

ThreadPool类提供一个线程池,该线程池可用于发送工作项、处理异步 I/O、代表其他线程等待以及处理计时器。该类提供一个由系统维护的线程池(可以看作一个线程的容器),该容器需要Windows 2000以上系统支持,因为其中某些方法调用了只有高版本的Windows才有的API函数。

下面介绍一下该类所提供的方法,如表1所示。

表1                          ThreadPool类的方法

方法

描述

BindHandle

将操作系统句柄绑定到ThreadPool

GetAvailableThreads

检索由GetMaxThreads方法返回的最大线程池线程数和当前活动线程数之间的差值

GetMaxThreads

检索可以同时处于活动状态的线程池请求的数目。所有大于此数目的请求将保持排队状态,直到线程池线程变为可用

GetMinThreads

检索线程池在新请求预测中维护的空闲线程数

QueueUserWorkItem

将方法排入队列以便执行。此方法在有线程池线程变得可用时执行

RegisterWaitForSingleObject

注册正在等待WaitHandle的委托

SetMaxThreads

设置可以同时处于活动状态的线程池的请求数目。所有大于此数目的请求将保持排队状态,直到线程池线程变为可用

SetMinThreads

设置线程池在新请求预测中维护的空闲线程数

UnsafeQueueNativeOverlapped

将重叠的 I/O 操作排队以便执行

UnsafeQueueUserWorkItem

注册一个等待 WaitHandle 的委托

UnsafeRegisterWaitForSingleObject

将指定的委托排队到线程池

通过以上方法,可以对线程池进行设置以及相应的操作,那么,我们什么时候使用线程池呢?我们在用Thread类调用线程时,一次只能使用一个线程来创建和删除线程,这种方式的建立和删除线程对CPU的使用是很频繁的,为了节省CPU的负荷,可以使用线程池对线程进行操作,为了使读者更深入的了解Thread类与ThreadPool类的差别。

在以下情况下,应使用ThreadPool类:

  1. 要以最简单的方式创建和删除线程;
  2. 应用程序使用线程的性能要优先考虑。
  3. 在以下情况下,应使用Thread类:
  4. 要控制所创建线程的优先级;
  5. 希望所使用的线程维护其标识,该标识要与线程一起进行各种操作,经过许多不同的时间段;
  6. 所使用的线程的寿命较长。

ThreadPool类会在线程的托管池中重用已有的线程。使用完线程后,线程就会返回线程池,供以后使用。ThreadPool有25个可用的线程(每个处理器)。

在使用线程池时,一般调用ThreadPool类的QueueUserWorkItem方法。

用户并不需要自已建立线程,只需要把要进行的操作写成函数,然后作为参数传递给ThreadPool类的QueueUserWorkItem方法就行了,传递的方法是依靠WaitCallback代理对象,而线程的建立、管理、运行等工作都是由系统自动完成的,用户无须考虑那些复杂的细节问题。ThreadPool类的用法:首先程序创建了一个ManualResetEvent对象,该对象就像一个信号灯,可以利用它的信号来通知其它线程。

4  线程池的设置

为了读者能更好的控制线程池,下面讲解一下如何设置和读取线程池的最大线程数和最小空闲线程数。

1.线程池的最大线程数

可排队到线程池的操作数仅受可用内存的限制;但是,线程池限制进程中可以同时处于活动状态的线程数。默认情况下,限制每个CPU可以使用25个辅助线程和1000 个I/O完成线程。

通过使用GetMaxThreads和SetMaxThreads方法可以控制最大线程数。下面对这两个方法的声明进行一下说明。

(1)GetMaxThreads方法

该方法检索可以同时处于活动状态的线程池请求的数目。所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。其语法如下:

public static void GetMaxThreads(out int workerThreads,out int completionPortThreads)

参数说明:

workerThreads:Int32,线程池中辅助线程的最大数目。

CompletionPortThreads:Int32,线程池中异步I/O线程的最大数目。

(2)SetMaxThreads方法

该方法设置可以同时处于活动状态的线程池的请求数目。所有大于此数目的请求将保持排队状态,直到线程池线程变为可用。

[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]public static bool SetMaxThreads(int workerThreads,int completionPortThreads)

参数说明:

workerThreads:Int32,线程池中辅助线程的最大数目。

CompletionPortThreads:Int32,线程池中异步 I/O 线程的最大数目。

返回值:bool型,如果更改成功,则为true;否则为false。

下面通过一段代码对GetMaxThreads和SetMaxThreads方法的应用进行一下讲解,主要是显示线程池中辅助线程的最大数和线程池中异步I/O线程的最大数,以及用户自行设置后的线程池情况。代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace ConsoleApplication1{class Program{static void Main(string[] args){//设置正在等待线程的事件为终止
AutoResetEvent autoEvent = new AutoResetEvent(false);int workerThreads;int portThreads;//获取处于活动状态的线程池请求的数目
ThreadPool.GetMaxThreads(out workerThreads, out portThreads);//在控制台中显示处于活动状态的线程池请求的数目

Console.WriteLine("设置前,线程池中辅助线程的最大数为:" + workerThreads.ToString() + ";线程池中异步I/O线程的最大数为:" + portThreads.ToString());workerThreads = 10;//设置辅助线程的最大数
portThreads = 500;//设置线程池中异步I/O线程的最大数//设置处于活动状态的线程池请求的数目
ThreadPool.SetMaxThreads(workerThreads, portThreads);ThreadPool.QueueUserWorkItem(new WaitCallback(ThreadMethod), autoEvent);//执行线程池//在控制台中显示设置后的处于活动状态的线程池请求的数目
Console.WriteLine("设置后,线程池中辅助线程的最大数为:" + workerThreads.ToString() + ";线程池中异步I/O线程的最大数为:" + portThreads.ToString());Console.ReadLine();}static void ThreadMethod(object stateInfo){Console.WriteLine("执行线程池");}}}

运行结果如下:

注意在 .NET Framework 1.0 和 1.1 版中,不能从托管代码中设置线程池大小。承载公共语言运行库的代码可以使用 mscoree.h 中定义的 CorSetMaxThreads 设置该大小。

2.线程池的最小空闲线程数

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

在启动新的空闲线程之前,线程池具有一个内置延迟(在 .NET Framework 2.0 版中为半秒钟)。应用程序在短期内定期启动许多任务时,空闲线程数的微小增加会导致吞吐量显著增加。将空闲线程数设置得过高会浪费系统资源。

使用GetMinThreads和SetMinThreads方法可以控制线程池所维持的空闲线程数。下面对这两个方法进行一下说明。

(1)GetMinThreads方法

该方法用于检索线程池在新请求预测中维护的空闲线程数。其语法如下:

public static void GetMinThreads(out int workerThreads,out int completionPortThreads)

参数说明:

workerThreads:Int32,当前由线程池维护的空闲辅助线程的最小数目。

CompletionPortThreads:Int32,当前由线程池维护的空闲异步I/O线程的最小数目。

(2)SetMinThreads方法

该方法用于设置线程池在新请求预测中维护的空闲线程数。其语法如下:

[SecurityPermissionAttribute(SecurityAction.Demand, ControlThread = true)]public static bool SetMinThreads(int workerThreads,int completionPortThreads)

参数说明:

workerThreads:类型:Int32,要由线程池维护的新的最小空闲辅助线程数。

CompletionPortThreads:Int32,要由线程池维护的新的最小空闲异步 I/O 线程数。

返回值:bool型,如果更改成功,则为 true;否则为 false。

下面用一段代码来详细说明一下GetMinThreads和SetMinThreads方法的应用,代码如下:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;namespace ConsoleApplication1{class Program{static void Main(string[] args){int minWorker, minIOC;//获取线程池在新请求预测中维护的默认空闲线程数
ThreadPool.GetMinThreads(out minWorker, out minIOC);Console.WriteLine("设置前,线程池维护的空闲辅助线程的最小数目为:" + minWorker.ToString() + ";线程池维护的空闲异步I/O线程的最小数目为:" + minIOC.ToString());//在控制台中显示线程池的默认空闲线程数
minWorker = 4;//设置线程池维护的空闲辅助线程的最小数
minIOC = 10;//设置线程池维护的空闲异步I/O线程的最小数if (ThreadPool.SetMinThreads(minWorker, minIOC))//如果更改成功
{Console.WriteLine("设置后,线程池维护的空闲辅助线程的最小数目为:" + minWorker.ToString() + ";线程池维护的空闲异步I/O线程的最小数目为:" + minIOC.ToString());//在控制台中显示更改后的线程池的默认空闲线程数
}else{Console.WriteLine("没有设置");}Console.ReadLine();}}}

运行结果如下:

注意:在.NET Framework 1.0版中,不能设置最小空闲线程数。

转载于:https://www.cnblogs.com/DonetRen/p/10167095.html

C#中的线程池使用(一)相关推荐

  1. Java5中的线程池实例讲解

    Java5增加了新的类库并发集java.util.concurrent,该类库为并发程序提供了丰富的API多线程编程在Java 5中更加容易,灵活.本文通过一个网络服务器模型,来实践Java5的多线程 ...

  2. java mina多线程_mina2中的线程池

    一.Mina中的线程池模型 前面介绍了Mina总体的层次结构,那么在Mina里面是怎么使用Java NIO和进行线程调度的呢?这是提高IO处理性能的关键所在.Mina的线程调度原理主要如下图所示: A ...

  3. Java-Java中的线程池原理分析及使用

    文章目录 概述 线程池的优点 线程池的实现原理 线程池的使用 创建线程池 向线程池中提交任务 关闭线程池 合理的配置线程池 线程池的监控 概述 我们在上篇博文 Java-多线程框架Executor解读 ...

  4. python停止线程池_详解python中Threadpool线程池任务终止示例代码

    需求 加入我们需要处理一串个位数(0~9),奇数时需要循环打印它:偶数则等待对应时长并完成所有任务:0则是错误,但不需要终止任务,可以自定义一些处理. 关键点 定义func函数处理需求 callbac ...

  5. 四十七、面试前,必须搞懂Java中的线程池ThreadPoolExecutor(上篇)

    @Author:Runsen @Date:2020/6/9 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  6. android中的线程池学习笔记

    阅读书籍: Android开发艺术探索 Android开发进阶从小工到专家 对线程池原理的简单理解: 创建多个线程并且进行管理,提交的任务会被线程池指派给其中的线程进行执行,通过线程池的统一调度和管理 ...

  7. 多线程线程池的实现java_如何在Java中实现线程池

    多线程线程池的实现java 线程是独立程序的执行路径. 在java中,每个线程都扩展java.lang.Thread类或实现java.lang.Runnable. 多线程是指在一个任务中同时执行两个或 ...

  8. 如何在Java中实现线程池

    线程是独立程序的执行路径. 在java中,每个线程都扩展java.lang.Thread类或实现java.lang.Runnable. 多线程是指在一个任务中同时执行两个或多个线程.在多线程中,每个任 ...

  9. java线程池怎么创建_java中的线程池,如何创建?

    Java中的线程池它是线程的容器,或者(换句话说,它是具有执行任务能力的线程的集合). 我们可以使用ThreadPool框架来定位(或实现)线程池. 线程池可以包含多个线程.每当我们执行任何任务时,线 ...

  10. JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecut

    JDK1.5中的线程池(java.util.concurrent.ThreadPoolExecut 在多线程大师Doug Lea的贡献下,在JDK1.5中加入了许多对并发特性的支持,例如:线程池. 一 ...

最新文章

  1. CSS的单位及css3的calc()及line-height百分比
  2. MPLSOAM技术及应用
  3. 7-CPU Reset
  4. java string底层实现_Java-学习日记(Shell与String底层原理)
  5. PHPCMS修改目录
  6. html div图片定位,html中div定位练习
  7. iPhone 14 Pro太空黑渲染图曝光:感叹号挖孔+直角边框
  8. 带货造假,买完不能换货?李佳琦、汪涵、李雪琴直播被中消协点名后这样回应...
  9. 中国各省会城市经纬度位置
  10. javaweb复习题库
  11. 关于hibernate的mappedBy的使用:
  12. ENVI哨兵一号数据处理
  13. 开启京东自动化领京豆
  14. zookeeper windows7下集群搭建
  15. 【第60题】必学的枚举1-枚举的定义和基本特性
  16. 实验二 实现中点分割直线段裁剪算法
  17. 分类指标计算 Precision、Recall、F-score、TPR、FPR、TNR、FNR、AUC、Accuracy
  18. 【Practical】蒙特卡罗法及其应用
  19. umijs在Jenkins上npm run buid,FATAL ERROR: Ineffective mark-compacts near heap limit Allocation fail...
  20. 通过宝塔面板,定时清除Docker日志空间

热门文章

  1. node.js 爬虫 实现爬取网页图片并保存到本地
  2. 高级Socket编程技术
  3. java 后端根据传入参数生成HTML并转换成Base64图片字节码(以及FTP上传常用)
  4. 解决jacob用wps将word转html的时候个别生僻字乱码的问题
  5. jquery事件使用方法总结
  6. 文字绘制——putText详解
  7. 关于freespace的调研
  8. springboot使用Validation API和全局异常优雅的校验方法参数
  9. Spring中@NotEmpty、@NotBlank、@NotNull 区别和使用
  10. 基于大肠杆菌的体外蛋白表达系统:myTXTL无细胞体外蛋白表达系统