线程池的介绍及简单实现(2)线程池的简单实现及对比测试
 
- UID
- 1066743
|

线程池的介绍及简单实现(2)线程池的简单实现及对比测试
线程池的简单实现及对比测试 一般一个简单线程池至少包含下列组成部分。
- 线程池管理器(ThreadPoolManager):用于创建并管理线程池
- 工作线程(WorkThread): 线程池中线程
- 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行。
- 任务队列:用于存放没有处理的任务。提供一种缓冲机制。
线程池管理器至少有下列功能:创建线程池,销毁线程池,添加新任务 创建线程池的部分代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
| …
//create threads
synchronized(workThreadVector)
{
for(int j = 0; j < i; j++)
{
threadNum++;
WorkThread workThread = new WorkThread(taskVector, threadNum);
workThreadVector.addElement(workThread);
}
}
…
|
注意同步workThreadVector并没有降低效率,相反提高了效率,请参考Brian Goetz的文章。 销毁线程池的部分代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| …
while(!workThreadVector.isEmpty())
{
if(debugLevel > 2)
System.out.println("stop:"+(i));
i++;
try
{
WorkThread workThread = (WorkThread)workThreadVector.remove(0);
workThread.closeThread();
continue;
}
catch(Exception exception)
{
if(debugLevel > 2)
exception.printStackTrace();
}
break;
}
…
|
添加新任务的部分代码如下:
1
2
3
4
5
6
7
| …
synchronized(taskVector)
{
taskVector.addElement(taskObj);
taskVector.notifyAll();
}
…
|
工作线程是一个可以循环执行任务的线程,在没有任务时将等待。由于代码比较多在此不罗列.
任务接口是为所有任务提供统一的接口,以便工作线程处理。任务接口主要规定了任务的入口,任务执行完后的收尾工作,任务的执行状态等。在文章结尾有相关代码的下载。
以上所描述的线程池结构很简单,一些复杂的线程池结构将不再此讨论。
在下载代码中有测试驱动程序(TestThreadPool),我利用这个测试程序的输出数据统计出下列测试结果。测试有两个参数要设置:
分别将一个参数固定,另一个参数变动以考察两个参数所产生的不同结果。所用测试机器分别为普通PC机(Win2000 JDK1.3.1)和SUN服务器(Solaris Unix JDK1.3.1),机器配置在此不便指明。
表1:测试数据及对应结果线程池尺寸任务数没有应用线程池所用的时间(单位:毫秒,OS:win)应用线程池所用的时间(单位:毫秒,OS:win)没有应用线程池所用的时间(单位:毫秒,OS:Solaris)15000389613065132500034551516221450003425120544885000347516057691650003505211578532500034552516403645000359550151821285000351588151542565000349531045502512500034255488566716120022162202021164201027168202022161630202916324020461664602072161281102014816256201202521651241140522161024811711233162048155280204516409628742504828
图1.线程池的尺寸的对服务器程序的性能影响 根据以上统计数据可得出下图:
图2.任务数对服务器程序的冲击 数据分析如下:
图1是改变线程池尺寸对服务器性能的影响,在该测试过程中,服务器的要完成的任务数固定为为5000。从图1中可以看出合理配置线程池尺寸对于大量任务处理的效率有非常明显的提高,但是一旦尺寸选择不合理(过大或过小)就会严重降低影响服务器性能。理论上"过小"将出现任务不能及时处理的情况,但在图表中显示出某些小尺寸的线程池表现很好,这是因为测试驱动中有很多线程同步开销,且这个开销相对于完成单个任务的时间是不能忽略的。"过大"则会出现线程间同步开销太大的问题,而且在线程间切换很耗CPU时间,在图表显示的很清楚。可见任何一个好技术,如果滥用都会造成灾难性后果。
图2是用不同数量的任务来冲击服务器程序,在该测试过程中,服务器线程池尺寸固定为16。可以看出线程池在处理少量任务时的优势不明显。所以线程池技术有一定的适应范围,关于适用范围将在后面讨论。但对于大量的任务的处理,线程池的优势表现非常卓越,服务器程序处理请求的时间虽然有波动,但是其平均值相对小多了。
值得注意的是测试方案中,统计任务的完成时间没有包含了创建线程池的时间。在实际线程池工作时,即利用线程池处理任务时,创建线程池的时间是不必计算在内的。
由于测试驱动程序有很多同步代码,特别是等待线程执行完毕的同步(代码中为sleepToWait(long l)方法的调用),这些代码降低了代码执行效率,这是测试驱动一个缺点,但这个测试驱动可以说明线程池相对于简单使用线程的优势。 |
|
|
|
|
|