为什么用线程池
有时候,系统需要处理非常多的执行时间很短的请求
,如果每一个请求都开启一个新线程的话
,系统就要不断的进行线程的创建和销毁
,有时花在创建和销毁线程上的时间
会比线程真正执行的时间还长
。而且当线程数量太多时
,系统不一定能受得了
使用线程池
主要为了解决一下几个问题:
降低资源消耗:通过重用线程池中的线程,来减少每个线程创建和销毁的性能开销
提高响应速度:当任务到达时,任务可以不需要等到线程创建就能立即执行
提高线程的可管理性:线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一维护和管理,分配、调优和监控
线程池规则
线程池
的线程执行规则
跟任务队列
有很大的关系。
下面都假设任务队列没有大小限制:
如果线程数量 <= 核心线程数量,那么 直接启动一个核心线程 来执行任务,不会放入队列中。
如果线程数量 > 核心线程数,但 <= 最大线程数,并且任务队列是LinkedBlockingDeque的时候,超过核心线程数量的任务会放在任务队列中排队。
如果线程数量 > 核心线程数,但 <= 最大线程数,并且任务队列是SynchronousQueue的时候,线程池会创建新线程执行任务,这些任务也不会被放在任务队列中。这些线程属于非核心线程,在任务完成后,闲置时间达到了超时时间就会被清除。
如果线程数量 > 核心线程数,并且 > 最大线程数,当任务队列是LinkedBlockingDeque,会将超过核心线程的任务放在任务队列中排队。也就是当任务队列是LinkedBlockingDeque并且没有大小限制时,线程池的最大线程数设置是无效的,他的线程数最多不会超过核心线程数。
如果线程数量 > 核心线程数,并且 > 最大线程数,当任务队列是SynchronousQueue的时候,会因为线程池 拒绝添加 任务而抛出异常。
任务队列大小有限时
当LinkedBlockingDeque塞满时,新增的任务会直接创建新线程来执行,当创建的线程数量超过最大线程数量时会抛异常。
SynchronousQueue没有数量限制。因为他根本不保持这些任务,而是直接交给线程池去执行。当任务数量超过最大线程数时会直接抛异常。
常用类
Executor
Executor是一个接口
,跟线程池有关的基本都要跟他打交道。下面是常用的ThreadPoolExecutor的关系
Executor接口
很简单,只有一个execute方法
ExecutorService
是Executor的子接口
,增加了一些常用的对线程的控制方法
,之后使用线程池主要也是使用这些方法
AbstractExecutorService
是一个抽象类
。ThreadPoolExecutor
就是实现了这个类
。
ThreadPoolExecutor
线程池的创建
构造方法
构造方法参数说明
-
corePoolSize
核心线程数
,默认情况下核心线程会一直存活
,即使处于闲置状态也不会受存keepAliveTime限制
。除非将allowCoreThreadTimeOut设置为true。当
提交一个任务到线程池
时,线程池会创建一个线程来执行任务
,即使其他空闲的基本线程能够执行新任务也会创建线程,等到需要执行的任务数大于线程池基本大小时就不再创建
。如果调用了prestartAllCoreThreads()方法
,线程池会提前创建并启动所有基本线程
-
maximumPoolSize
线程池所能容纳的最大线程数
。超过这个数的线程将被阻塞
。当任务队列为没有设置大小的LinkedBlockingDeque时,这个值无效
。
如果队列满了
,并且已创建的