一、线程池概念
线程池是指在初始化一个多线程应用程序过程中创建一个线程集合,由于单个线程的创建和销毁需要开辟单独的线程内存空间和资源,所以频繁的创建和销毁线程也是需要系统开销的,线程池可以将使用完成的线程暂时回收到线程池中,避免重复创建和销毁带来的资源消耗问题。
二、为什么要有线程池?
-
线程池改进了一个应用程序的响应时间。由于线程池中的线程已经准备好且等待被分配任务,应用程序可以直接拿来使用而不用新建一个线程。
-
线程池节省了CLR (运行时环境)为每个短生存周期任务创建一个完整的线程的开销并可以在任务完成后回收资源。
-
线程池根据当前在系统中运行的进程来优化线程时间片。
-
线程池允许我们开启多个任务而不用为每个线程设置属性。
-
线程池允许我们为正在执行的任务的程序参数传递一个包含状态信息的对象引用。
-
线程池可以用来解决处理一个特定请求最大线程数量限制问题。
三、线程池的类的继承关系
四、ThreadPoolExecutor 的研究
ThreadPoolExecutor 的构造函数最全的为7个参数,源码如下:
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize || //核心线程数不能大于最大线程池数
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException(); //线程队列、线程工厂、拒绝策略不为null
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
可看到使用此构造函数直接创建线程池,线程池各个参数解释如下:
int corePoolSize:核心线程池数量,线程池创建后保持的数量
int maximumPoolSize:线程池最大线程数量,大于这个数则只需Rejected策略
long keepAliveTime:空闲线程存活的最大时间,超过这个时间则回收
TimeUnit unit: 空闲线程存活的最大时间单位设置
BlockingQueue workQueue:core线程数满后存放任务需要的阻塞队列
ThreadFactory threadFactory: 线程创建工厂,可以指定自定义的线程池名称等
RejectedExecutionHandler handler:自定义拒绝策略,如果任务数量大于maximumPoolSize则执行此策略。
五、Executors静态工厂六种常用线程池
1、SingleThreadPool(单线程线程池)
这个线程池只有一个线程在工作,也就是相当于单线程串行执行所有任务。如果这个唯一的线程因为异常结束,那么会有一个新的线程来替代它。此线程池保证所有任务的执行顺序按照任务的提交顺序执行。
2、FixedThreadPool(固定大小线程池)
每次提交一个任务就创建一个线程,直到线程达到线程池的最大大小。线程池的大小一旦达到最大值就会保持不变,如果某个线程因为执行异常而结束,那么线程池会补充一个新线程。
3、CachedThreadPool(弹性缓存线程池)
如果线程池的大小超过了处理任务所需要的线程,那么就会回收部分空闲(60秒不执行任务)的线程,当任务数增加时,此线程池又可以智能的添加新线程来处理任务。此线程池不会对线程池大小做限制,线程池大小完全依赖于操作系统(或者说JVM)能够创建的最大线程大小。
4、ScheduledThreadpool(定时器线程池)
此线程池支持定时以及周期性执行任务的需求。
5、WorkStealingPool(工作隐藏线程池)
6、ForkJoinPool(叉形接头线程池)