线程池的技术背景
在面向对象编程中,由于创建一个对象获取内存资源或者其他更多资源,创建和销毁对象是很费时间和资源的。在java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务效率的一种方式便是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。
如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些“池化资源”技术产生的原因。
线程池技术如何提高服务器程序的性能
我所提到服务器程序是指能够接受客户请求并能处理请求的程序,而不只是指那些接受网络客户请求的网络服务器程序。
多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。
线程池的简单实现及对比测试
一般一个简单线程池至少包含下列组成部分。
1. 线程池管理器(ThreadPollManager):用于创建并管理线程池
2. 工作线程(WorkThread):线程池中线程
3. 任务接口(Task):每个任务必须实现的接口,以供工作线程调度任务的执行
4. 任务队列:用于存放没有处理的任务,提供一种缓冲机制。
线程管理器:应该具有创建和管理线程的功能
下列是创建线程池的部分代码:
private final int i=100;//Thread Pool size
private int threadNum =0;
//create threads
synchronized(workThreadVector){
for(int j=0;j<i;j++){
threadNum++;
WorkThread workThread = new WorkThread(taskVector,threadNum);
workThreadVector.addElement(workThread);
}
}
注意同步workThreadVector并没有降低效率,相反提高了效率。(??)Vector的相关知识可参考
下列是销毁线程池的部分代码:
while(!workThreadVector.isEmpty()){
if(debugLevel > 2)
System.out.println("stop:"+(i));
i++;
try{
WorkThread workThread = (WorkThread)workThreadVector.remove(0)
workThread.closeThread();
continue;
}catch(Exception ex){
if(debugLevel > 2)
ex.printStackTrace();
}
break;
}
synchronized(taskVector){
taskVector.addElement(taskObj);
taskVector.notifyAll();
}
工作线程是一个可以循环执行任务的线程,在没有任务时将等待。
任务接口是为所有任务提供统一的接口,以便工作线程处理。
关于高级线程池的探讨
简单线程池存在一些问题,比如如果有大量的客户要求服务器为其服务,但由于线程池的工作线程是有限的,服务器智能为部分客户服务,服务器只能为部分客户服务,其他客户提交的任务,只能在任务队列中等待处理。一些系统设计人员可能会不满这种状况,因为他们对服务器程序的响应时间要求比较严格,所以在系统设计时可能会怀疑线程池技术的可行性,但是线程池有相应的解决方案。调整优化线程池尺寸是高线线程池要解决的一个问题。主要有下列解决方案:
方案一:动态增加工作线程
在一些高级线程池中一般提供一个可以动态改变的工作线程数目的功能,以适应突发性的请求。线程增加可以采用一种超前方式,即批量增加一批工作线程,而不是来一个请求才建立创建一个线程。批量创建时更加有效的方式。该方案还应该限制线程池中工作线程数目的上限和下限。
举例:Jini中的TaskManager,就是一个精巧线程池管理器,它是动态增加工作线程的。SQL Server采用单进程(Single Process)多线程(Multi-Thread)的系统结构,1024个数量的线程池,动态线程分配, 理论上限32767.
方案二:优化工作线程数目
如果不想在线程池应用复杂的策略来保证工作线程数满足应用的要求,你就要根据统计学的原理来统计客户的请求数目,比如高峰时段平均一秒钟内有多少任务要处理,并根据系统的承受能力及客户的忍受能力来平衡估计一个合理的线程池尺寸。
举例:在MTS中线程池的尺寸固定为100.
方案三:一个服务器提供多个线程池
在一些复杂的系统结构会采用这个方案。这样可以根据不同任务或者任务优先级来采用不同线程池处理。
举例:COM+用到了多个线程池.
线程池技术使用范围及应注意的问题
线程池的应用范围:
1. 需要大量的线程来完成任务,且完成任务的时间比较短。WEB服务器完成网页请求这样的任务,使用线程池技术非常合适。因为单个任务小,而任务数量巨大。
但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet会话时间比线程的创建时间大多了。
2. 对性能要求苛刻的应用,比如要求服务器迅速相应客户请求。
3. 接受突发性的大量请求,但不至于使服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池情况下,将产生大量线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,并出现“OutOfMemory”的错误。
参考资料:http://www.ibm.com/developerworks/cn/java/l-threadPool/