1 线程池技术介绍
在面向对象编程中,创建和销毁对象是很费时间的,因为创建一个对象要获取内存资源或者其它更多资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能够在对象销毁后进行垃圾回收。所以提高服务程序效率的一个手段就是尽可能减少创建和销毁对象的次数,特别是一些很耗资源的对象创建和销毁。如何利用已有对象来服务就是一个需要解决的关键问题,其实这就是一些"池化资源"技术产生的原因。比如大家所熟悉的数据库连接池正是遵循这一思想而产生的,本文将介绍的线程池技术同样符合这一思想。
诸如Web服务器、数据库服务器、文件服务器和邮件服务器等许多服务器应用程序都需要处理一种常见的情况:单个任务处理的时间很短而请求的数目却是巨大的。假设我们构建一个简单服务器应用程序模型:每当一个请求到达就创建一个新的服务对象,然后在新的服务对象中为请求服务。服务器程序利用线程技术响应客户请求已经司空见惯,可能您认为这样做效率已经很高,但是当我们遇到大量的客户并发地访问应用服务器时采用这种服务器模型会有很多问题。我们采用线程池技术来解决这种单个任务处理时问很短而请求数目却是巨大的这样的难题。
目前,一些著名的大公司都特别看好这项技术,并早已经在他们的产品中应用该技术。比如IBM的WebSphere,IONA的Orbix 2000在SUN的Jini中,Microsoft的MTS(MicrosoftTransaction Server 2.0),COM+等。
2 引入线程池技术的原因
在应用服务器中需要处理从客户端发起的任务请求,这些任务往往具有高密度、短时间的特性。无论通过什么方式在服务器得到客户端请求后,服务器都需要独立地处理这个客户请求。针对这个问题,线程池提供了处理系统性能和大用户量请求之间的矛盾的方法。通过对多个任务重用已经存在的线程对象,降低了对线程对象创建和销毁的开销。当客户请求时,线程对象已经存在,可以提高请求的响应时间,从而整体地提高了系统服务的表现。
多线程技术主要解决处理器单元内多个线程执行的问题,它可以使处理器尽量保持忙碌状态,充分利用系统的可用资源,使得系统的性能得到显著提高。但是如果对多线程技术应用不当的话,也会事与愿违,可以通过一个简单的例子来说明这一点。
线程执行过程分为三个部分:T1、T2、T3。其中T1表示线程创建的时间,T2表示线程执行任务所需时间,包括线程间同步所需时间,T3表示线程销毁时间。那么我们可以看出,执行任务所需时间T为T1+T2+T3,然而真正处理任务的时间为T2,线程本身的开销为T1、T3两部分之和,这样线程开销占总时间的比例为(T1+T3)/(T1+T2+T3)。如果任务处理的时间T2比较短小,那创建和销毁的开销所占的比例将会非常大,因而如何减少T1和T3两部分时间是需要解决的问题。线程池正是着眼于减少T1和T3这两部分时间的开销,使得系统的效率提高。他把T1和T3分别安排在服务器程序启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时就不会T1和T3开销了。
3 线程池技术优点
线程池技术有着如下几个方面的优点:
(1)可以控制产生线程的数量。通过预先创建一定数量的工作线程并限制其数量,控制线程对象的内存消耗。
(2)降低系统开销和资源消耗。通过对多个请求重用线程、线程创建、销毁的开销被分摊到了多个请求上。另外就是通过限制线程数量、降低系统在垃圾回收方面的开销。
(3)提高系统响应速度。线程事先已被创建,请求到达时可直接进行处理,消除了因线程创建所带来的时间延迟,另外多个线程可以并发处理。
(4)Java线程池的编程模型相对于原有的多线程编程模型来说,还有一大改进,那就是线程代码和业务代码的分离。
4线程池工作原理
一般来说实现一个线程池主要包括以下几个组成部分:
(1)线程管理器:用于创建并管理线程池。
(2)工作线程:线程池中实际执行任务的线程。在初始化线程时会预先创建好固定数目的线程在池中,这些初始化的线程一般是处于空闲状态,不消耗CPU,占用较小的内存空间。
(3)任务接口:每个任务必须实现的接口,当线程池中的可执行的任务时,被工作线程调试执行。把任务抽象出来形成任务接口,可以做到线程池与具体的任务无关。
(4)任务队列:用来存放没有处理的任务,提供一种缓冲机制。实现这种结构有好几种方法,常用的是队列,主要是利用它先进先出的工作原理;另外一种是链表之类的数据结构,可以动态为它分配内存空间,应用中比较灵活。我们用到的是链表数据结构形式来实现任务队列。