线程池原理
开始优化之前,我们先来看看线程池的实现原理,有助于你更好地理解后面的内容。
在HotSpot VM的线程模型中,Java线程被一对一映射为内核线程。Java在使用线程执行程序时,需要创建一个内核线程;当该Java线程被终止时,这个内核线程也会被回收。因此Java线程的创建与销毁将会消耗一定的计算机资源,从而增加系统的性能开销。
除此之外,大量创建线程同样会给系统带来性能问题,因为内存和CPU资源都将被线程抢占,如果处理不当,就会发生内存溢出、CPU使用率超负荷等问题。
为了解决上述两类问题,Java提供了线程池概念,对于频繁创建线程的业务场景,线程池可以创建固定的线程数量,并且在操作系统底层,轻量级进程将会把这些线程映射到内核。
线程池可以提高线程复用,又可以固定最大线程使用量,防止无限制地创建线程。当程序提交一个任务需要一个线程时,会去线程池中查找是否有空闲的线程,若有,则直接使用线程池中的线程工作,若没有,会去判断当前已创建的线程数量是否超过最大线程数量,如未超过,则创建新线程,如已超过,则进行排队等待或者直接抛出异常。
线程池框架Executor
Java最开始提供了ThreadPool实现了线程池,为了更好地实现用户级的线程调度,更有效地帮助开发人员进行多线程开发,Java提供了一套Executor框架。
这个框架中包括了ScheduledThreadPoolExecutor和ThreadPoolExecutor两个核心线程池。前者是用来定时执行任务,后者是用来执行被提交的任务。鉴于这两个线程池的核心原理是一样的,下面我们就重点看看ThreadPoolExecutor类是如何实现线程池的。
Executors实现了以下四种类型的ThreadPoolExecutor:
Executors利用工厂模式实现的四种线程池,我们在使用的时候需要结合生产环境下的实际场景。不过我不太推荐使用它们,因为选择使用Executors提供的工厂类,将会忽略很多线程池的参数设置,工厂类一旦选择设置默认参数,就很容易导致无法调优参数设置,从而产生性能问题或者资源浪费。
这里我建议你使用ThreadPoolExecutor自我定制一套线程池。进入四种工厂类后,我们可以发现除了newScheduledThreadPool类,其它类均使用了ThreadPoolExecutor类进行实现,你可以通过以下代码简单看下该方法:
public ThreadPoolExecutor(int corePoolSize,//线程池的核心线程数量
int maximumPoolSize,//线程池的最大线程数
long keepAliveTime,//当线程数大于核心线程数时,多余的空闲线程存活的最长时间
TimeUnit unit,//时间单位
Bloc