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

本文涉及的产品
云数据库 RDS SQL Server,独享型 2核4GB
简介:


在面向对象编程中,经常会面对创建对象和销毁对象的情况,如果不正确处理的话,在短时间内创建大量对象然后执行简单处理之后又要销毁这些刚刚建立的对象,这是一个非常消耗性能的低效行为,所以很多面向对象语言中在内部使用对象池来处理这种情况,以提高性能,比如在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的例子,代码如下:
 
InBlock.gif using System.Threading; 
InBlock.gif using System.Collections; 
InBlock.gif using System.Diagnostics; 
InBlock.gif using System; 
InBlock.gif using System.ComponentModel; 
InBlock.gif 
InBlock.gif namespace ThreadPoolDemo 
InBlock.gif
InBlock.gif         class ThreadPoolDemo1 
InBlock.gif        { 
InBlock.gif                 public ThreadPoolDemo1() 
InBlock.gif                { 
InBlock.gif                } 
InBlock.gif 
InBlock.gif                 public  void Work() 
InBlock.gif                { 
InBlock.gif                        ThreadPool.QueueUserWorkItem( new WaitCallback(CountProcess)); 
InBlock.gif                        ThreadPool.QueueUserWorkItem( new WaitCallback(GetEnvironmentVariables)); 
InBlock.gif                } 
InBlock.gif                 /// <summary> 
InBlock.gif                 /// 统计当前正在运行的系统进程信息 
InBlock.gif                 /// </summary> 
InBlock.gif                 /// <param name="state"></param> 
InBlock.gif                 private  void CountProcess( object state) 
InBlock.gif                { 
InBlock.gif                        Process[] processes = Process.GetProcesses(); 
InBlock.gif                         foreach (Process p  in processes) 
InBlock.gif                        { 
InBlock.gif                                 try 
InBlock.gif                                { 
InBlock.gif                                        Console.WriteLine( "Id:{0},ProcessName:{1},StartTime:{2}", p.Id, p.ProcessName, p.StartTime); 
InBlock.gif                                } 
InBlock.gif                                 catch (Win32Exception e) 
InBlock.gif                                { 
InBlock.gif                                        Console.WriteLine( "ProcessName:{0}", p.ProcessName); 
InBlock.gif                                } 
InBlock.gif                                 finally 
InBlock.gif                                { 
InBlock.gif                                } 
InBlock.gif                        } 
InBlock.gif                        Console.WriteLine( "获取进程信息完毕。"); 
InBlock.gif                } 
InBlock.gif                 /// <summary> 
InBlock.gif                 /// 获取当前机器系统变量设置 
InBlock.gif                 /// </summary> 
InBlock.gif                 /// <param name="state"></param> 
InBlock.gif                 public  void GetEnvironmentVariables( object state) 
InBlock.gif                { 
InBlock.gif                        IDictionary list=System.Environment.GetEnvironmentVariables(); 
InBlock.gif                         foreach (DictionaryEntry item  in list) 
InBlock.gif                        { 
InBlock.gif                                Console.WriteLine( "key={0},value={1}", item.Key, item.Value); 
InBlock.gif                        } 
InBlock.gif                        Console.WriteLine( "获取系统变量信息完毕。"); 
InBlock.gif                } 
InBlock.gif 
InBlock.gif   static  void Main( string[] args) 
InBlock.gif                { 
InBlock.gif                        ThreadPoolDemo1 tpd1 =  new ThreadPoolDemo1(); 
InBlock.gif                        tpd1.Work(); 
InBlock.gif                        Thread.Sleep(5000); 
InBlock.gif 
InBlock.gif                        Console.WriteLine( "OK"); 
InBlock.gif 
InBlock.gif                        Console.ReadLine(); 
InBlock.gif                } 
InBlock.gif        } 
InBlock.gif
上面这段代码在本机的运行情况如下:
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 服务器中,可以使用线程池来处理来自客户端的请求,可以以比较高的性能运行。



















本文转自周金桥51CTO博客,原文链接: http://blog.51cto.com/zhoufoxcn/263696  ,如需转载请自行联系原作者

相关实践学习
使用SQL语句管理索引
本次实验主要介绍如何在RDS-SQLServer数据库中,使用SQL语句管理索引。
SQL Server on Linux入门教程
SQL Server数据库一直只提供Windows下的版本。2016年微软宣布推出可运行在Linux系统下的SQL Server数据库,该版本目前还是早期预览版本。本课程主要介绍SQLServer On Linux的基本知识。 相关的阿里云产品:云数据库RDS&nbsp;SQL Server版 RDS SQL Server不仅拥有高可用架构和任意时间点的数据恢复功能,强力支撑各种企业应用,同时也包含了微软的License费用,减少额外支出。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/sqlserver
相关文章
|
1月前
|
Java C#
C#学习系列相关之多线程(五)----线程池ThreadPool用法
C#学习系列相关之多线程(五)----线程池ThreadPool用法
|
1月前
|
Java
线程池中的空余线程是如何被回收的
线程池中的空余线程是如何被回收的
27 1
|
22天前
|
存储 算法 Java
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
【C/C++ 线程池设计思路】 深入探索线程池设计:任务历史记录的高效管理策略
68 0
|
19天前
|
Java 测试技术 Python
Python开启线程和线程池的方法
Python开启线程和线程池的方法
13 0
Python开启线程和线程池的方法
|
29天前
|
负载均衡 Java 数据处理
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用(三)
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用
50 2
|
29天前
|
存储 监控 Java
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用(二)
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用
35 1
|
29天前
|
负载均衡 安全 Java
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用(一)
【C++ 并发 线程池】轻松掌握C++线程池:从底层原理到高级应用
57 2
|
1月前
|
Java easyexcel 应用服务中间件
【二十五】springboot使用EasyExcel和线程池实现多线程导入Excel数据
【二十五】springboot使用EasyExcel和线程池实现多线程导入Excel数据
157 0
|
1月前
|
存储 Java
什么是线程池,线程池的状态,线程池的用法示例
什么是线程池,线程池的状态,线程池的用法示例
|
1月前
|
安全 Java 程序员
多线程案例-线程池
多线程案例-线程池

热门文章

最新文章