为什么要使用线程池?
许多服务器应用程序,例如Web服务器,数据库服务器,文件服务器或邮件服务器,都是围绕处理大量来自某个远程源的简短任务而设计的。 请求以某种方式到达服务器,该方式可能是通过网络协议(例如HTTP,FTP或POP),通过JMS队列,或者可能是通过轮询数据库。 不管请求如何到达,在服务器应用程序中,通常每个任务的处理都是短暂的,并且请求的数量很大。
用于构建服务器应用程序的一种简化模型是,每次请求到达时创建一个新线程,并在新线程中处理该请求。 这种方法实际上可以很好地用于原型制作,但是有很多明显的缺点,如果您尝试部署以这种方式工作的服务器应用程序,这些缺点将变得显而易见。 每个请求线程方法的缺点之一是为每个请求创建一个新线程的开销很大。 如果服务器为每个请求创建一个新线程,则与处理实际用户请求相比,它会花费更多的时间并花费更多的系统资源来创建和销毁线程。
除了创建和销毁线程的开销外,活动线程还会消耗系统资源。 由于过多的内存消耗,在一个JVM中创建太多线程可能会导致系统内存不足或崩溃。 为了防止资源崩溃,服务器应用程序需要某种方式来限制在任何给定时间正在处理多少个请求。
线程池为线程生命周期开销问题和资源崩溃问题提供了解决方案。 通过将线程重用于多个任务,线程创建开销分散在许多任务上。 另外,由于在请求到达时线程已经存在,因此消除了线程创建带来的延迟。 因此,可以立即为请求提供服务,从而使应用程序更具响应性。 此外,通过适当地调整线程池中的线程数,可以通过强制超过某个阈值的任何请求等待直到有线程可以处理它来防止资源崩溃。
线程池的替代方法
线程池不是在服务器应用程序中使用多个线程的唯一方法。 如上所述,有时候为每个新任务生成一个新线程是完全明智的。 但是,如果任务创建的频率很高且平均任务持续时间很短,则为每个任务生成新线程将导致性能问题。
另一个常见的线程模型是具有单个后台线程和用于某种类型任务的任务队列。 AWT和Swing使用此模型,其中有一个GUI事件线程,并且导致用户界面更改的所有工作都必须在该线程中执行。 但是,由于只有一个AWT线程,因此不希望在AWT线程中执行可能要花费明显时间才能完成的任务。 结果,Swing应用程序通常需要其他工作线程来长时间运行与UI相关的任务。
每个任务线程和单后台线程方法在某些情况下都可以很好地工作。 “每任务线程”方法与少量长时间运行的任务配合得很好。 只要调度的可预测性不重要&#x