简述
在面向软件编程中,创建和销毁对象是一件非常耗时的事情,因为创建一个对象要获取内存资源或者其它更多的资源。在Java中更是如此,虚拟机将试图跟踪每一个对象,以便能在对象销毁时进行回收。所以提供程序效率的方法就是减少对象的创建和销毁。如何利用已有的对象来服务就是一个需要解决的问题。
Java线程池实现了一个Java高并发的、Java多线程的、可管理的统一调度器。java.util.concurrent.Executors工作中最常用的和熟知的,顺便一提,java.util.concurrent包由出自著名的大神Doug Lea之手。
Executors是个线程工厂类,方便快速地创建很多线程池,也可以说是一个线程池工具类。配置一个线程池是比较复杂的,尤其是对于线程池原理不是很清楚的情况下,很可能配置的线程池不是最优的,以至于达不到预期的效果,因此Executors类里面给我们提供了一些静态工厂方法,以便我们能生成常用的线程池。
常用的方法有如下三种:
- 1、newSingleThreadExecutor:创建一个单线程的线程池。
- 2、newFixedThreadPool:创建固定大小的线程池。
- 3、newCachedThreadPool:创建一个可缓存的线程池。
1、newSingleThreadExecutor的使用
创建一个单线程的线程池。这个线程只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常而结束,那么会有一个新的线程来代替它。此线程保证所有的任务的执行顺序按照任务的提交顺序执行。
运行结果如下所示:
2、newCachedThreadPool的使用
创建一个缓冲池大小可根据需要伸缩的线程池,但是在以前构造的线程可用时将重用它们。对于执行很多短期异步任务而言,这些线程池通常可提供程序性能。调用execute将重用以前构造的线程(如果线程可用)。如果现有线程没有可用的,则创建一个新线程并添加到池中。终止并从缓存中移除那些已有60s未被使用的线程。因此,长时间保持空闲的线程池不会使用任何资源。
Demo:
3、newFixedThreadPool的使用
创建一个可重用固定线程数的线程池,以共享的无界队列方式来运行这些线程。在任意点,在大多数nThreads线程会处于处理任务的活动状态。如果在所有线程处于活动状态时提交附加任务,则在有可用线程之前,附加任务将在队列中等待。如果在关闭前的执行期间由于失败而导致任何线程终止,那么一个新的线程将代替它执行后续任务(如果需要)。在某个线程被显示关闭之前,池中的线程将一直存在。
Demo:
运行结果如下:
线程池的好处
1、合理利用线程能带来4个好处
(1). 降低资源消耗。通过重复利用已创建的线程,降低线程创建和销毁造成的消耗。
(2). 提供响应速度。当任务到达时,任务可以不需要等待线程创建就能立即执行。
(3).提供线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。但是要做到合理地利用线程,必须对其原理了如指掌。
(4).防止服务器过载,形成内存溢出,或者CPU耗尽。
2、线程池技术如何高服务器程序的性能
这里所提及的服务器程序是指能够接收客户端请求并处理请求的程序,而不只是那些接受 络客户端请求的 络服务器程序。多线程技术主要解决处理器单元内多个线程执行的问题,它可以显著减少处理器单元的闲置时间,增加处理器单元的吞吐能力。但如果对多线程应用不当,会增加对单个任务的处理时间。
3、举个栗子
假设在一台服务器完成一项任务的时间为T,并假设:
* T1,创建线程的时间。
* T2,在线程中执行任务所花费的时间,包括线程同步所需时间
* T3,线程销毁时间
显然T=T1+T2+T3。这是一个极度简化的假设栗子。
可以看出T1、T3是多线程本身带来的开销,我们渴望减少T1、T3所用的时间从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建和销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1、T3),而不是优点(并发性)。
线程池技术正是关注如何缩短调整T1、T3时间的技术,从而提高服务器程序性能的。它把T1、T3分别安排在服务器程序启动或结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户端请求时,不会有T1、T3的开销了。
线程池不仅调整了T1、T3产生的时间段,而且它还显著减少了创建线程的数目。再看一个栗子:
假设一个服务器一天要处理50000个请求,并且每个请求需要一个单独的线程数目完成。我们比较一下利用线程技术和不利用线程池技术的服务器处理这些请求时所产生的线程总数。在线程池中,线程数一般是固定的,所以产生线程的总数不会超过线程池中的数目或者上限(以下简称线程池尺寸),而如果服务器不利用线程池来处理这些请求则线程总数为50000.一般线程池尺寸是远远小于50000的。所以利用线程池的服务器程序不会为了创建50000而在处理请求时浪费时间,从而提高整体效率。
4、线程池应用范围
(1)需要大量的线程来完成任务,且完成任务的时间比较短。Web服务器完成 页请求这样的任务,使用多线程池技术是非常合适的。因为单个任务小,而任务数量巨大,你可以想象一个热门 站的点击次数。但对于长时间的任务,比如一个Telnet连接请求,线程池的优点就不明显了。因为Telnet回话时间比线程的创建时间打多了。
(2)对性能要求苛刻的应用,比如要求服务器迅速响应客户端请求。
(3)接收突发性的大量请求,但不至于使用服务器因此产生大量线程的应用。突发性大量客户请求,在没有线程池的情况下,将产生大量的线程,虽然理论上大部分操作系统线程数目最大值不是问题,短时间内产生大量线程可能使内存到达极限,并出现OutOfMemory的错误。
The End:Next:线程池的工作机制及其原理
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!