Java基础教程:多线程基础——线程池
线程池
在正常负载的情况瞎,通过为每一个请求创建一个新的线程来提供服务,从而实现更高的响应性。
new Thread(runnable).start()
在生产环境中,为每一个任务分配一个线程的方法存在一些缺陷,尤其是需要创建大量线程时:
- 线程生命周期的开销非常高。线程的创建和销毁是需要代价的。
- 资源消耗。如果可运行线程数量多于可用处理器数量,那么有些线程将会闲置。大量空闲的线程将会占用许多内存,给垃圾回收器带来压力,而且大量线程在竞争CPU资源时还将产生其他的性能开销。
- 随着平台的不同,在可创建线程的数量其实会存在限制,而并非无限制。
一个简单的例子,当某个恶意的用户或者过多用户,使得Web服务器的负载达到某个阙值,将会导致服务器崩溃。
线程池,是指管理一组具有相同构造的工作线程的资源池。线程池是与工作队列密切相关的,工作队列中保存了所有等待执行的任务,每个工作线程从工作队列中获取一个任务,执行任务,然后返回线程池并等待下一个任务。
“在线程池中执行任务”比“为每一个任务分配一个线程”优势更多。通过重用现有的线程而不是创建新线程,可以在处理多个请求时分摊在线程创建和销毁过程中产生的巨大开销。另外,当请求达到时,工作线程通常已经存在,因此不会由于等待创建线程而延迟任务的执行。通过适当调整线程池的大小,可以创建足够多的线程以便使处理器保持忙碌状态,同时还可以防止过多线程相互竞争资源而使应用程序耗尽内存或失败。
线程池的创建
可以通过Executors中的静态工厂方法来创建一个线程池:
- newFixedThreadPool:固定线程数量的线程池。
- newCachedThreadPool:一个可缓存的线程池,可随着规模和处理需求动态调整线程池大小。
- newSingleThreadExecutor:单线程的执行器,确保所有线程在队列中串行执行。
- newScheduledThreadPool:创建一个固定长度的线程池,而且以延迟或定时的方式来执行任务。
线程池的关闭
为了解决执行服务的生命周期问题,ExecutorService扩展了Executor接口,并添加了一些用于声明周期管理的方法。ExecutorService的声明周期有三个:
- 运行:ExecutorService在创建初期处于运行状态。
- 关闭:详见下面两个方法。
- 终止:等待所有任务都完成后,ExecutorService处于终止状态。可以轮询isTerminated()来判断是否进入了终止状态。