可设置的主要参数
- corePoolSize
核心线程数,核心线程会一直存活,即使没有任务需要处理。当线程数小于核心线程数时,即使现有的线程空闲,线程池也会优先创建新线程来处理任务,而不是直接交给现有的线程处理。
核心线程在allowCoreThreadTimeout被设置为true时会超时退出,默认情况下不会退出。
- maxPoolSize
当线程数大于或等于核心线程,且任务队列已满时,线程池会创建新的线程,直到线程数量达到maxPoolSize。如果线程数已等于maxPoolSize,且任务队列已满,则已超出线程池的处理能力,线程池默认会拒绝处理任务而抛出异常。可以自定义处理多余任务的RejectedExecutionHandler
该参数在某些情况下是无效的。
- keepAliveTime
当已经执行过的线程空闲后,空闲时间小于keepAliveTime,又来了新的任务时,会直接启动该线程。
当线程空闲时间达到keepAliveTime,该线程会退出,直到线程数量等于corePoolSize。
如果allowCoreThreadTimeout设置为true,则所有线程均会退出直到线程数量为0。
- allowCoreThreadTimeout
是否允许核心线程空闲退出,默认值为false。
- queueCapacity
任务队列容量,由它设定一个有界的队列。从maxPoolSize的描述上可以看出,任务队列的容量会影响到线程的变化,因此任务队列的长度也需要恰当的设置。
-
RejectedExecutionHandler
public interface RejectedExecutionHandler { void rejectedExecution(Runnable r, ThreadPoolExecutor executor); }
任务拒绝处理策略。在源码中定义了如下几种策略:
- AbortPolicy (默认策略)
public static class AbortPolicy implements RejectedExecutionHandler { public AbortPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { throw new RejectedExecutionException("Task " + r.toString() + " rejected from " + e.toString()); } }
该策略 直接抛出了异常。异常中止
- CallerRunsPolicy
public static class CallerRunsPolicy implements RejectedExecutionHandler { public CallerRunsPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { r.run(); } } }
在线程池未关闭时,直接在当前线程执行任务。所谓当前线程,即提交任务时的线程
- DiscardPolicy
public static class DiscardPolicy implements RejectedExecutionHandler { public DiscardPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { } }
不做任何处理,即跳过任务r
- DiscardOldestPolicy
public static class DiscardOldestPolicy implements RejectedExecutionHandler { public DiscardOldestPolicy() { } public void rejectedExecution(Runnable r, ThreadPoolExecutor e) { if (!e.isShutdown()) { e.getQueue().poll(); e.execute(r); } } }
在线程池未关闭时,移除处于队头的任务,再执行任务r。相当于把之前队头的任务跳过了,把r又加入了队列
参数对线程池任务调度的影响
当任务数大于等于corePoolSize,这时,除核心线程执行了一定数量的任务后,
余下的需要执行的任务数为int count = tasksCount - corePoolSize
,设队列最大容量为capacity:
-
若
capacity >= count
,则只会创建corePoolSize个线程来执行任务。多的任务放在队列中。这时maxPoolSize,就无效了
-
若
capacity < count
,这时有int remain = tasksCount - capacity
:- 若
remain <= maxPoolSize
,创建remain个线程来执行任务。多的任务放在队列中 - 若
remain > maxPoolSize
,创建maxPoolSize个线程来执行任务;这时将有remain-maxPoolSize
个任务无法加入队列,被RejectedExecutionHandler处理。
- 若
Executors生成ThreadPoolExecutor
(most from http://dongxuan.iteye.com/blog/901689)
在构建时,corePoolSize、maximumPoolSizes 和BlockingQueue的选择,直接影响线程调度的策略
Executors 有三个方法可以生成 ThreadPoolExecutor
生成一个固定线程数的 ThreadPoolExecutor
public static ExecutorService newFixedThreadPool(int nThreads) {
? return new ThreadPoolExecutor(nThreads, nThreads,
? 0L, TimeUnit.MILLISECONDS,
? new LinkedBlockingQueue());
}
LinkedBlockingQueue实现是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选,LinkedBlockingQueue 可以指定容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。在ThreadPoolExecutor中主要使用的是BlockingQueue的offer()和 poll()、take()
LinkedBlockingQueue 无界队列
生成一个只含一个线程的ThreadPoolExecutor
public static ExecutorService newSingleThreadExecutor() {
? return new FinalizableDelegatedExecutorService
? (new ThreadPoolExecutor(1, 1,
? 0L, TimeUnit.MILLISECONDS,
? new LinkedBlockingQueue()));
}
LinkedBlockingQueue 无界队列
生成一个无界的并直接提交的ThreadPoolExecutor
pub