`
caobihole
  • 浏览: 950113 次
文章分类
社区版块
存档分类
最新评论

多线程编程(3):线程池ThreadPool

 
阅读更多

在面向对象编程中,经常会面对创建对象和销毁对象的情况,如果不正确处理的话,在短时间内创建大量对象然后执行简单处理之后又要销毁这些刚刚建立的对象,这是一个非常消耗性能的低效行为,所以很多面向对象语言中在内部使用对象池来处理这种情况,以提高性能,比如在ADO.NET内部就允许使用数据库连接池来提高性能,在JDBC中没有提供数据库连接池,一些开发人员为了提高效率就自己编写数据库连接池来提高性能,当然据我所知在Java中有些框架提供了数据库连接的池化处理。

在多线程编程时也会遇到上面的情况,如果创建了过多的线程将会增加操作系统资源的占用,并且还要处理资源要求和潜在的占用冲突,并且使用了多线程之后将使代码的执行流程和资源竞争情况变得复杂,稍不留心就会产生bug(在第二篇中在我写的代码中就曾经出现过一个bug,后来我自己发现并处理了这个bug)。在使用多线程编程时对需要同步的资源访问尤其需要注意,如系统资源(系统端口等)、共享资源(文件、窗口句柄等)、属于单个应用程序的资源(如全局、静态和实例字段或属性)。

针对上面的情况,我们可以使用线程池来解决上面的大部分问题,跟使用单个线程相比,使用线程池有如下优点:

1、缩短应用程序的响应时间。因为在线程池中有线程的线程处于等待分配任务状态(只要没有超过线程池的最大上限),无需创建线程。

2、不必管理和维护生存周期短暂的线程,不用在创建时为其分配资源,在其执行完任务之后释放资源。

3、线程池会根据当前系统特点对池内的线程进行优化处理。

总之使用线程池的作用就是减少创建和销毁线程的系统开销。在.NET中有一个线程的类ThreadPool,它提供了线程池的管理。

ThreadPool是一个静态类,它没有构造函数,对外提供的函数也全部是静态的。其中有一个QueueUserWorkItem方法,它有两种重载形式,如下:

public static bool QueueUserWorkItem(WaitCallback callBack):将方法排入队列以便执行。此方法在有线程池线程变得可用时执行。

public static bool QueueUserWorkItem(WaitCallback callBack,Object state):将方法排入队列以便执行,并指定包含该方法所用数据的对象。此方法在有线程池线程变得可用时执行。

QueueUserWorkItem方法中使用的的WaitCallback参数表示一个delegate,它的声明如下:

public delegate void WaitCallback(Object state)

如果需要传递任务信息可以利用WaitCallback中的state参数,类似于ParameterizedThreadStart委托。

下面是一个ThreadPool的例子,代码如下:

上面这段代码在本机的运行情况如下:

key=Path,value=C:/WINDOWS/system32;C:/WINDOWS;C:/WINDOWS/System32/Wbem;C:/Program Files/Microsoft SQL Server/80/Tools/BINN;C:/Program Files/Microsoft SQL Server/80/Tools/Binn/;C:/Program Files/Microsoft SQL Server/90/DTS/Binn/;C:/Program Files/Microsoft SQL Server/90/Tools/binn/;C:/Program Files/Microsoft SQL Server/90/Tools/Binn/VSShell/Common7/IDE/;C:/Program Files/Microsoft Visual Studio 8/Common7/IDE/PrivateAssemblies/;C:/MySQL Server 5.1/bin;C:/php-5.2.9-Win32

key=TEMP,value=C:/DOCUME~1/ZHOUFO~1/LOCALS~1/Temp

key=SESSIONNAME,value=Console

key=PATHEXT,value=.COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH

key=Rav,value=C:/Documents and Settings/All Users/Application Data/Rising/Rav

key=PROCESSOR_ARCHITECTURE,value=x86

key=SystemDrive,value=C:

key=APPDATA,value=C:/Documents and Settings/zhoufoxcn/Application Data

key=windir,value=C:/WINDOWS

key=USERPROFILE,value=C:/Documents and Settings/zhoufoxcn

key=TMP,value=C:/DOCUME~1/ZHOUFO~1/LOCALS~1/Temp

key=USERDOMAIN,value=ZHOU

key=ProgramFiles,value=C:/Program Files

key=FP_NO_HOST_CHECK,value=NO

key=HOMEPATH,value=/Documents and Settings/zhoufoxcn

key=COMPUTERNAME,value=ZHOU

key=USERNAME,value=zhoufoxcn

key=NUMBER_OF_PROCESSORS,value=2

key=PROCESSOR_IDENTIFIER,value=x86 Family 6 Model 15 Stepping 13, GenuineIntel

key=SystemRoot,value=C:/WINDOWS

key=ComSpec,value=C:/WINDOWS/system32/cmd.exe

key=LOGONSERVER,value=//ZHOU

key=CommonProgramFiles,value=C:/Program Files/Common Files

key=PROMPT,value=$P$G

key=PROCESSOR_LEVEL,value=6

key=PROCESSOR_REVISION,value=0f0d

key=VS80COMNTOOLS,value=C:/Program Files/Microsoft Visual Studio 8/Common7/Tools/

key=lib,value=C:/Program Files/SQLXML 4.0/bin/

key=ALLUSERSPROFILE,value=C:/Documents and Settings/All Users

key=VS90COMNTOOLS,value=c:/Program Files/Microsoft Visual Studio 9.0/Common7/Tools/

key=OS,value=Windows_NT

key=HOMEDRIVE,value=C:

获取系统变量信息完毕。

Id:1864,ProcessName:mysqld,StartTime:2010-1-11 8:23:25

Id:3732,ProcessName:HTime,StartTime:2010-1-11 8:32:16

Id:1328,ProcessName:spoolsv,StartTime:2010-1-11 8:23:23

Id:3908,ProcessName:ctfmon,StartTime:2010-1-11 8:32:19

Id:3640,ProcessName:cmd,StartTime:2010-1-11 15:43:04

Id:1488,ProcessName:notepad,StartTime:2010-1-11 15:30:48

Id:3668,ProcessName:conime,StartTime:2010-1-11 15:27:22

Id:964,ProcessName:svchost,StartTime:2010-1-11 8:23:22

Id:1408,ProcessName:svchost,StartTime:2010-1-11 8:23:23

Id:1140,ProcessName:svchost,StartTime:2010-1-11 8:23:22

Id:1940,ProcessName:sqlbrowser,StartTime:2010-1-11 8:23:25

Id:1672,ProcessName:MsDtsSrvr,StartTime:2010-1-11 8:23:24

Id:3540,ProcessName:explorer,StartTime:2010-1-11 8:32:14

Id:3268,ProcessName:wps,StartTime:2010-1-11 14:08:00

Id:1568,ProcessName:inetinfo,StartTime:2010-1-11 8:23:24

Id:588,ProcessName:csrss,StartTime:2010-1-11 8:23:17

Id:3704,ProcessName:360tray,StartTime:2010-1-11 8:32:16

Id:1028,ProcessName:svchost,StartTime:2010-1-11 8:23:22

Id:2184,ProcessName:mqtgsvc,StartTime:2010-1-11 8:23:28

Id:2628,ProcessName:Reflector,StartTime:2010-1-11 15:04:35

Id:3872,ProcessName:devenv,StartTime:2010-1-11 15:26:51

Id:204,ProcessName:ThreadPoolDemo,StartTime:2010-1-11 15:43:26

Id:664,ProcessName:winlogon,StartTime:2010-1-11 8:23:20

Id:840,ProcessName:dexplore,StartTime:2010-1-11 14:50:21

Id:3900,ProcessName:rundll32,StartTime:2010-1-11 8:32:18

Id:1636,ProcessName:mdm,StartTime:2010-1-11 8:23:24

Id:1012,ProcessName:RavMonD,StartTime:2010-1-11 8:23:22

Id:1100,ProcessName:svchost,StartTime:2010-1-11 8:23:22

Id:476,ProcessName:smss,StartTime:2010-1-11 8:23:14

Id:920,ProcessName:svchost,StartTime:2010-1-11 8:23:21

Id:716,ProcessName:services,StartTime:2010-1-11 8:23:21

Id:3052,ProcessName:ThreadPoolDemo.vshost,StartTime:2010-1-11 15:42:27

Id:1448,ProcessName:msdtc,StartTime:2010-1-11 8:23:23

Id:180,ProcessName:mqsvc,StartTime:2010-1-11 8:23:25

Id:2512,ProcessName:iexplore,StartTime:2010-1-11 14:52:29

Id:1888,ProcessName:nvsvc32,StartTime:2010-1-11 8:23:25

Id:728,ProcessName:lsass,StartTime:2010-1-11 8:23:21

Id:2240,ProcessName:alg,StartTime:2010-1-11 8:23:28

Id:3808,ProcessName:jusched,StartTime:2010-1-11 8:32:17

Id:3128,ProcessName:RsTray,StartTime:2010-1-11 8:32:17

Id:1992,ProcessName:svchost,StartTime:2010-1-11 8:23:25

Id:2944,ProcessName:Foxit Reader,StartTime:2010-1-11 14:08:48

Id:4,ProcessName:System,StartTime:1601-1-1 8:00:00

Id:1604,ProcessName:jqs,StartTime:2010-1-11 8:23:24

ProcessName:Idle

获取进程信息完毕。

OK

在上面的代码中我们使用了线程池,并让它执行了两个任务,一个是列出系统当前所有环境变量的值,一个是列出系统当前运行的进程名和它们的启动时间。

当然,优点和缺点总是同时存在的,使用ThreadPool也有一些缺点,使用线程池有如下缺点:

1、一旦加入到线程池中就没有办法让它停止,除非任务执行完毕自动停止;

2、一个进程共享一个线程池;

3、要执行的任务不能有返回值(当然,线程中要执行的方法也是不能有返回值,如果确实需要返回值必须采用其它技巧来解决);

4、在线程池中所有任务的优先级都是一样的,无法设置任务的优先级;

5、不太适合需要长期执行的任务(比如在Windows服务中执行),也不适合大的任务;

6、不能为线程设置稳定的关联标识,比如为线程池中执行某个特定任务的线程指定名称或者其它属性。

如果我们要面临的情况正好是线程池的缺点,那么我们只好继续使用线程而不是线程池。不过在某些情况下使用线程池确实可以带来很多方便的,比如在WEB服务器中,可以使用线程池来处理来自客户端的请求,可以以比较高的性能运行。

分享到:
评论

相关推荐

    PyQt5中多线程模块QThread和线程池ThreadPoolExecutor解决PyQt5界面程序执行比较耗时操作无响应问题

    1.资源简介:PyQt5中使用多线程模块QThread解决了PyQt5界面程序执行比较耗时操作时,程序卡顿出现的无响应以及界面输出无法实时显示的问题,采用线程池ThreadPoolExecutor解决了ping多个IP多任务耗时问题。...

    c#多线程线程池和异步编程

    我们将在这里进一步讨论一些.NET类,以及他们在多线程编程中扮演的角色和怎么编程。它们是:  System.Threading.ThreadPool 类  System.Threading.Timer 类  如果线程的数目并不是很多,而且你想控制每个线程的...

    92道Java多线程与并发面试题含答案(很全)

    Java并发编程的核心概念包括: 线程(Thread):线程是程序执行流的最小单元。...原子操作(Atomic Operations):原子操作是不可中断的操作,即在多线程环境中,这些操作要么完全执行,要么完全不执行。

    基于C++11 实现的动态线程池源码示例.zip

    基于C++11 实现的动态线程池源码示例.zip 【资源说明】 使用 C++11 实现的动态线程池,主要特性: 使用简单,不易出错。 支持线程复用,提升性能。 支持懒惰创建线程。 必要时自动回收空闲的线程。 【快速上手】 #...

    异步/多线程/任务/并行编程之一:如何选择合适的多线程模型?

    @多线程编程模型的选择。  1:异步、多线程、任务、并行的本质 这四个概念对应在CLR中的本质,本质都是多线程。 异步,简单的讲就是BeginInvoke、EndInvoke模式,它在CLR内部线程池进行管理; 多线程,体现在C#中,...

    深入解析C++编程中线程池的使用

    传 统多线程方案中我们采用的服务器模型则是一旦接受到请求之后,即创建一个新的线程,由该线程执行任务。任务执行完毕后,线程退出,这就是是“即时创建,即 时销毁”的策略。尽管与创建进程相比,创建线程的时间...

    并发编程示例,涉及到AtomicXXX、CountDownLatch、线程池等

    并发编程的一些小示例 1.等待通知的几种方式,包括Object的wait/notify,Condition的await/signal 2. CountDownLatch,统一控制多线程开始和结束 3.原子操作,AtomicXXX 4.线程池

    Visual.C#.编程精彩百例

    实例42 线程池(ThreadPool)的应用 实例43 多线程互斥运行 实例44 多线程时钟应用程序 实例45 监视多线程 实例46 防止多线程应用程序死锁 实例47 文件同步操作与应用 实例48 在COM程序设计中使用.NET组件 ...

    Visual Basic.NET线程参考手册

    3.5 端到端的示例 3.5.1 编写自己的线程安全包装器 3.5.2 数据库连接池 3.6 本章小结第4章 设计模式 4.1 应用程序中的多线程 4.2 STA线程模式 4.3 MTA线程模式 4.3.1 指定线程模式 4.3.2 设计线程应用程序 4.3.3 ...

    threadpool-0_2_5-src.rar_进程与线程_C++_

    多线程编程,线程池类库,boost library封装实现,例程有merge sort等等

    C++多线程与网络应用

    线程池应用,结合socket编程,将收数据、发数据,数据处理分别让不同线程进行处理,以得到高性能。

    基于threadpool和network的网络聊天室

    1、开启线程池、等待客户端连接 2、接收客户端名字,告诉所有的在线的客户端,XXX进入聊天室。 3、接收客户端消息,转发给其他客户端。 4、通知其他客户端 xxx退出聊天室 5、同时在线人数最多50人。 注意:任何...

    《Visual.C#.编程精彩百例》配套光盘.part2

    实例39 单个线程同步运行 实例40 多线程同步运行 实例41 线程Thread Relative Static跟踪与实现 实例42 线程池(ThreadPool)的应用 实例43 多线程互斥运行 实例44 多线程时钟应用程序 ...

    《Visual.C#.编程精彩百例》配套光盘part1

    实例39 单个线程同步运行 实例40 多线程同步运行 实例41 线程Thread Relative Static跟踪与实现 实例42 线程池(ThreadPool)的应用 实例43 多线程互斥运行 实例44 多线程时钟应用程序 ...

    java8源码-SpringTree:互联网通用技术

    java8 源码 SpringTree ...1.7提供的多线程框架已经与JDK 1.8 lamda的关系 采用工作窃取模式(当前线程任务执行完成,可窃取其他线程的执行任务),将大任务分解成多个小任务,最后将结果join 7:分布式锁 red

    ZLToolKit:一个基于C++11的轻量级网络框架,基于线程池技术可以实现大并发网络IO

    支持linux、macos、ios、android、windows平台了解更多:特性网络库tcp/udp客户端,接口简单易用并且是线程安全的,用户不必关心具体的socket api操作。tcp服务器,使用非常简单,只要实现具体的tcp会话(TcpSession...

Global site tag (gtag.js) - Google Analytics