前面我们提到了ExecutorService结构中的一个工厂类,Executors。这个类提供了一系列构造ExecutorService实例的方法。
这些方法的核心就是两个类,分别是 ThreadPoolExecutor
和 ScheduledThreadPoolExecutor
类。(当然还有别的类,比较常用的就是这两个)
今天介绍的就是 ThreadPoolExecutor
。
简介
这个类 的包名 java.util.concurrent.ThreadPoolExecutor
它当然也实现了 ExecutorService
接口
参照官网链接的描述:链接
ExecutorService 在 执行每一个提交的task的时候都是使用线程池内的线程来完成,而且 ExecutorService在配置的时候大部分都是使用Executors提供的方法。
线程池解决了两个不同的问题:
1.他通过(reduced per-task invocation overhead “简化的什么…… 实在不会翻译”)方法,提升了在执行大量异步任务时的性能。
2.他提供了一系列管理资源的方法,包括线程,当在执行异步任务的时候就会开始消耗资源。(当然ThreadPoolExecutor自身也会持有一些静态变量)
在ThreadPoolExecutor的构造方法中,提供了一些参数。这些参数可以根据我们不同的需求来进行对应的配置。 但是官方还是希望我们使用 Executors中提供的工厂方法,这样更加方便,这些提前配置好的方法能够满足大部分的使用场景,但是通过一些配置参数也是可以完成私人定制的。
私人定制
既然是私人定制就不得不提到其中的参数。
(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue< Runnable > workQueue)
Core and maximum pool sizes
corePoolSize
和 maximumPoolSize
这两个参数相当重要,他的值决定了当一个task执行的时候,thread 是如何分配的。
下面这张图大概的介绍了,当一个新task 由 ThreadPoolExecutor执行的时候内部运行的情况。
图中提到的 “根据corePoolSize
和 maximumPoolSize
判断”,就是根据 running thread 的数量判断,下面我们来分析使用。
(1) 运行状态线程 < corePoolSize
“fewer than corePoolSize threads are running”
当一个新的task通过 `execute`方法提交之后,如果这时 ThreadPoolExecutor中 "运行线程"的数量 满足 条件
那么ThreadPoolExecutor会新开线程来执行这个任务,即使存在其他的 闲置线程(idle)没有使用。
(2) 运行状态线程 >= corePoolSize && 运行状态线程 < maximumPoolSize (并且 queue not full )
“more than corePoolSize but less than maximumPoolSize”
如果处于(2)这种条件,那么新的task将会进入queue中,
(3) 在满足(2)的前提下,queue is full (队列已经满了)
如果处于(3)这种条件,那么新的task进来,就会new Thread来执行新的task。
(4)queue is full && 运行状态线程 >=maximumPoolSize
如果处于(4)这种条件,那么新进来 task 直接会被 reject。这个task是无法得到执行的。
(5)
这里其实也要注意一点,那就是Queue的类型,如果Queue是有界的,当然就会出现上面的四种情况。
但是如果 Queue是 无界的(不存在full)那么 `运行状态线程` 是永远也不会超过 corePoolSize 的值。
keepAliveTime
这个参数负责当前 ThreadPoolExecutor
管理的 Thread
能够存活的时间。
管理方法:
如果当前线程池中 运行状态线程 >corePoolSize,那么 其他处于 idle状态,并且存活时间 >keepAliveTime 线程就会被 终结。
这个参数在线程池处于不是很活跃的状态的时候可以有效地节约 资源的消耗。
BlockingQueue
这个容器 就是用来存放Task的,一般分为三个种类, 后面的文章会介绍到。
On-demand construction
除了这些构造函数能够初始化以外,还有一些特殊的方法能够进行初始化。
工厂方法:
Executors.newCachedThreadPool()
这个方法构建了一个 无界的线程池,它会自动完成线程的回收。
/**
* Creates a thread pool that creates new threads as needed, but
* will reuse previously constructed threads when they are
* available. These pools will typically improve the performance
* of programs that execute many short-lived asynchronous tasks.
* Calls to {@code execute} will reuse previously constructed
* threads if available. If no existing thread is available, a new
* thread will be created and added to the pool. Threads that have
* not been used for sixty seconds are terminated and removed from
* the cache. Thus, a pool that remains idle for long enough will
* not consume any resources. Note that pools with similar
* properties but different details (for example, timeout parameters)
* may be created using {@link ThreadPoolExecutor} constructors.
*
* @return the newly created thread pool
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
我们看出 maximumPoolSize 这个参数给的是 无穷大。至于Queue的选择,后面的文章会讲述Queue。
Executors.newSingleThreadExecutor()
这个方法构建了一个单线程的调度机制
/**
* Creates an Executor that uses a single worker thread operating
* off an unbounded queue. (Note however that if this single
* thread terminates due to a failure during execution prior to
* shutdown, a new one will take its place if needed to execute
* subsequent tasks.) Tasks are guaranteed to execute
* sequentially, and no more than one task will be active at any
* given time. Unlike the otherwise equivalent
* {@code newFixedThreadPool(1)} the returned executor is
* guaranteed not to be reconfigurable to use additional threads.
*
* @return the newly created single-threaded Executor
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
Executors.newFixedThreadPool
这个方法实现了固定线程数量的线程池
/**
* Creates a thread pool that reuses a fixed number of threads
* operating off a shared unbounded queue, using the provided
* ThreadFactory to create new threads when needed. At any point,
* at most {@code nThreads} threads will be active processing
* tasks. If additional tasks are submitted when all threads are
* active, they will wait in the queue until a thread is
* available. If any thread terminates due to a failure during
* execution prior to shutdown, a new one will take its place if
* needed to execute subsequent tasks. The threads in the pool will
* exist until it is explicitly {@link ExecutorService#shutdown
* shutdown}.
*
* @param nThreads the number of threads in the pool
* @param threadFactory the factory to use when creating new threads
* @return the newly created thread pool
* @throws NullPointerException if threadFactory is null
* @throws IllegalArgumentException if {@code nThreads <= 0}
*/
public static ExecutorService newFixedThreadPool(int nThreads, ThreadFactory threadFactory) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
threadFactory);
}
可以看到 corePoolSize 和 maximumPoolSize的值是一样的。