先看类简介:
An {@link ExecutorService} that executes each submitted task using
one of possibly several pooled threads, normally configured
using {@link Executors} factory methods.
线程池主要解决两个问题:处理大量任务时有更好的表现;提供很多可调节的参数以及扩展钩子,上下文切换更有用。
程序员更偏向使用:
Executors#newCachedThreadPool;不限制大小的线程池,并自动回收线程
Executors#newFixedThreadPool,固定大小的线程池
Executors#newSingleThreadExecutor,单个后台线程
<p>Thread pools address two different problems: they usually
provide improved performance when executing large numbers of
asynchronous tasks, due to reduced per-task invocation overhead,
and they provide a means of bounding and managing the resources,
including threads, consumed when executing a collection of tasks.
Each {@code ThreadPoolExecutor} also maintains some basic
statistics, such as the number of completed tasks.
<p>To be useful across a wide range of contexts, this class
provides many adjustable parameters and extensibility
hooks. However, programmers are urged to use the more convenient
{@link Executors} factory methods {@link
Executors#newCachedThreadPool} (unbounded thread pool, with
automatic thread reclamation), {@link Executors#newFixedThreadPool}
(fixed size thread pool) and {@link
Executors#newSingleThreadExecutor} (single background thread), that
preconfigure settings for the most common usage
scenarios. Otherwise, use the following guide when manually
configuring and tuning this class:
<dl>
<dt>Core and maximum pool sizes</dt>
ThreadPoolExecutor 会自动调整线程池大小 getPoolSize(),通过 corePoolSize getCorePoolSize() 和 maximumPoolSize getMaximumPoolSize();
当新任务通过 execute()提交时,并且运行的线程数量少于 corePoolSize,即使其他的线程是空闲的,也会创建一个新的线程来处理这个请求。如果运行的线程数量,大于 corePoolSize,
小于 maximumPoolSize,仅当队列满的时候,一个新得线程才会被创建(当队列不满的时候,会首先放入队列中)。
如果设置的 corePoolSize 等于 maximumPoolSize,会创建一个固定大小的线程池。
如果设置的 maximumPoolSize 无限大,比如等于 Integer.MAX_VALUE,允许无限多的任务并发处理。
典型的做法是,通过构造方法来设置 corePoolSize和 maximumPoolSize,但也可以通过 setCorePoolSize 和 setMaximumPoolSize 来动态设置。
<dd>A {@code ThreadPoolExecutor} will automatically adjust the
pool size (see {@link #getPoolSize})
according to the bounds set by
corePoolSize (see {@link #getCorePoolSize}) and
maximumPoolSize (see {@link #getMaximumPoolSize}).
When a new task is submitted in method {@link #execute(Runnable)},
and fewer than corePoolSize threads are running, a new thread is
created to handle the request, even if other worker threads are
idle. If there are more than corePoolSize but less than
maximumPoolSize threads running, a new thread will be created only
if the queue is full. By setting corePoolSize and maximumPoolSize
the same, you create a fixed-size thread pool. By setting
maximumPoolSize to an essentially unbounded value such as {@code
Integer.MAX_VALUE}, you allow the pool to accommodate an arbitrary
number of concurrent tasks. Most typically, core and maximum pool
sizes are set only upon construction, but they may also be changed
dynamically using {@link #setCorePoolSize} and {@link
#setMaximumPoolSize}. </dd>
<dt>On-demand construction</dt>
按需构造
一般来说,只有任务到达的时候,核心线程才会被初始化创建,但是这可以通过 prestartCoreThread或者 prestartAllCoreThreads来动态重写。
当使用一个非空队列来创建的时候,可能想要预热一些线程
<dd>By default, even core threads are initially created and
started only when new tasks arrive, but this can be overridden
dynamically using method {@link #prestartCoreThread} or {@link
#prestartAllCoreThreads}. You probably want to prestart threads if
you construct the pool with a non-empty queue. </dd>
<dt>Creating new threads</dt>
通过 ThreadFactory创建一个新的线程.如果不是特殊情况,通过 Executors#defaultThreadFactory创建的线程,都是在同一个线程组中,拥有相同的优先级和非守护状态。
通过提供一个不同的 ThreadFactory,可以修改线程名称、线程组、优先级、守护状态等等。。
如果 ThreadFactory通过 newThread() 创建线程时返回了null,不能再执行任何的任务。
线程应该有 modifyThread(运行时权限),如果使用线程池的工作线程或其他线程没有这个权限,服务可能会被降级:配置不会被即时生效
<dd>New threads are created using a {@link ThreadFactory}. If not
otherwise specified, a {@link Executors#defaultThreadFactory} is
used, that creates threads to all be in the same {@link
ThreadGroup} and with the same {@code NORM_PRIORITY} priority and
non-daemon status. By supplying a different ThreadFactory, you can
alter the thread's name, thread group, priority, daemon status,
etc. If a {@code ThreadFactory} fails to create a thread when asked
by returning null from {@code newThread}, the executor will
continue, but might not be able to execute any tasks. Threads
should possess the "modifyThread" {@code RuntimePermission}. If
worker threads or other threads using the pool do not possess this
permission, service may be degraded: configuration changes may not
take effect in a timely manner, and a shutdown pool may remain in a
state in which termination is possible but not completed.</dd>
<dt>Keep-alive times</dt>
池中当前线程的数量大于 corePoolSize,过多的空闲线程在超时(getKeepAliveTime)后会被中断。当线程池不活跃的时候,可以减少资源浪费。
之后当线程池再次活跃时,新的线程会被创建。这个参数也可以通过(setKeepAliveTime)来动态的改变。将值设置为 Integer.MAX_VALUE 可以阻止线程在终止之前被关闭。
一般来说,keep-alive 策略只是在数量多于 corePoolSize 时生效。但是方法(allowCoreThreadTimeOut)也可以在核心线程上应用这个策略,只要 keepAliveTime 非0.
<dd>If the pool currently has more than corePoolSize threads,
excess threads will be terminated if they have been idle for more
than the keepAliveTime (see {@link #getKeepAliveTime(TimeUnit)}).
This provides a means of reducing resource consumption when the
pool is not being actively used. If the pool becomes more active
later, new threads will be constructed. This parameter can also be
changed dynamically using method {@link #setKeepAliveTime(long,
TimeUnit)}. Using a value of {@code Long.MAX_VALUE} {@link
TimeUnit#NANOSECONDS} effectively disables idle threads from ever
terminating prior to shut down. By default, the keep-alive policy
applies only when there are more than corePoolSize threads. But
method {@link #allowCoreThreadTimeOut(boolean)} can be used to
apply this time-out policy to core threads as well, so long as the
keepAliveTime value is non-zero. </dd>
<dt>Queuing</dt>
任何的 BlockingQueue 都可能被用来转移和持有提交的任务.队列的使用和池的大小相互影响:
1.如果少于corePoolSize数量的线程在运行,Executes总是增加新的进程,而不放入队列
2.如果大于等于corePoolSize数量的线程在运行,Executes总是入队而不创建新的线程
3.当一个请求不能入队时,除非超过了 maximumPoolSize,会创建新的线程,否则,任务会被拒绝。
<dd>Any {@link BlockingQueue} may be used to transfer and hold
submitted tasks. The use of this queue interacts with pool sizing:
<ul>
<li> If fewer than corePoolSize threads are running, the Executor
always prefers adding a new thread
rather than queuing.</li>
<li> If corePoolSize or more threads are running, the Executor
always prefers queuing a request rather than adding a new
thread.</li>
<li> If a request cannot be queued, a new thread is created unless
this would exceed maximumPoolSize, in which case, the task will be
rejected.</li>
</ul>
There are three general strategies for queuing:
<ol>
一般来说,对于入队有3个策略:
1、直接传送.对于直接传送任务而不持有任务来说,SynchronousQueue是一个好的默认选择。如果没有可用的线程,尝试入队的任务就会失败,因此一个新的线程会被创建。
直接传送需要不限制大小的 maximumPoolSize,避免新提交的任务失败。
2、无界队列,使用无界队列如(LinkedBlockingQueue),当所有的线程(corePoolSize)都在忙的时候,会导致新的任务等待。
因此,不超过corePoolSize数量的线程都会被创建(maximumPoolSize不再起任何作用)。当任务相互独立时,可能比较合适,因此任务不能影响其他任务的执行;
3、有界队列。一个有界队列(ArrayBlockingQueue),有限的 maximumPoolSize 有助于预防资源枯竭。但是也更难协调和控制。
队列大小和池的大小相互影响:使用一个大的队列和小的池可以最小化cpu使用、系统资源、上下文切换,但是也会导致人为的低吞吐量。
如果任务频繁阻塞(例如I/O限制),系统调度的线程数量可能比你允许的还要大。使用一个小的队列,通常需要更大的线程池,这会充分利用cpu但会碰到不可接受的调度开销,
这也会降低吞吐量
<li> <em> Direct handoffs.</em> A good default choice for a work
queue is a {@link SynchronousQueue} that hands off tasks to threads
without otherwise holding them. Here, an attempt to queue a task
will fail if no threads are immediately available to run it, so a
new thread will be constructed. This policy avoids lockups when
handling sets of requests that might have internal dependencies.
Direct handoffs generally require unbounded maximumPoolSizes to
avoid rejection of new submitted tasks. This in turn admits the
possibility of unbounded thread growth when commands continue to
arrive on average faster than they can be processed. </li>
<li><em> Unbounded queues.</em> Using an unbounded queue (for
example a {@link LinkedBlockingQueue} without a predefined
capacity) will cause new tasks to wait in the queue when all
corePoolSize threads are busy. Thus, no more than corePoolSize
threads will ever be created. (And the value of the maximumPoolSize
therefore doesn't have any effect.) This may be appropriate when
each task is completely independent of others, so tasks cannot
affect each others execution; for example, in a web page server.
While this style of queuing can be useful in smoothing out
transient bursts of requests, it admits the possibility of
unbounded work queue growth when commands continue to arrive on
average faster than they can be processed. </li>
<li><em>Bounded queues.</em> A bounded queue (for example, an
{@link ArrayBlockingQueue}) helps prevent resource exhaustion when
used with finite maximumPoolSizes, but can be more difficult to
tune and control. Queue sizes and maximum pool sizes may be traded
off for each other: Using large queues and small pools minimizes
CPU usage, OS resources, and context-switching overhead, but can
lead to artificially low throughput. If tasks frequently block (for
example if they are I/O bound), a system may be able to schedule
time for more threads than you otherwise allow. Use of small queues
generally requires larger pool sizes, which keeps CPUs busier but
may encounter unacceptable scheduling overhead, which also
decreases throughput. </li>
</ol>
</dd>
<dt>Rejected tasks</dt>
当 Executes 被关闭的时候,以及池的 maximum和工作队列容量都已经饱和的时候,通过(execute)提交新的任务会被拒绝。
在这种情况下,execute方法会 invoke 调用 RejectedExecutionHandler#rejectedExecution()方法,提供有4中处理策略:
1、默认 ThreadPoolExecutor.AbortPolicy ,拒绝的时候,处理器抛出来一个运行时异常(RejectedExecutionException)
2、ThreadPoolExecutor.CallerRunsPolicy,线程调用execute自身来运行这个任务。这提供了一个简单的回调控制机制,来减慢新任务提交的频率。
3、ThreadPoolExecutor.DiscardPolicy,任务会被简单的丢弃。
4、ThreadPoolExecutor.DiscardOldestPolicy,如果 execute没有关闭,任务队列前头的任务会被丢弃,然后 execution会重试(可能会再次失败)
定义使用其他类型的 RejectedExecutionHandler 类时可能的。这样做需要当心,特别是当策略被设计并工作在特定容量或者队列策略下。
<dd>New tasks submitted in method {@link #execute(Runnable)} will be
<em>rejected</em> when the Executor has been shut down, and also when
the Executor uses finite bounds for both maximum threads and work queue
capacity, and is saturated. In either case, the {@code execute} method
invokes the {@link
RejectedExecutionHandler#rejectedExecution(Runnable, ThreadPoolExecutor)}
method of its {@link RejectedExecutionHandler}. Four predefined handler
policies are provided:
<ol>
<li> In the default {@link ThreadPoolExecutor.AbortPolicy}, the
handler throws a runtime {@link RejectedExecutionException} upon
rejection. </li>
<li> In {@link ThreadPoolExecutor.CallerRunsPolicy}, the thread
that invokes {@code execute} itself runs the task. This provides a
simple feedback control mechanism that will slow down the rate that
new tasks are submitted. </li>
<li> In {@link ThreadPoolExecutor.DiscardPolicy}, a task that
cannot be executed is simply dropped. </li>
<li>In {@link ThreadPoolExecutor.DiscardOldestPolicy}, if the
executor is not shut down, the task at the head of the work queue
is dropped, and then execution is retried (which can fail again,
causing this to be repeated.) </li>
</ol>
It is possible to define and use other kinds of {@link
RejectedExecutionHandler} classes. Doing so requires some care
especially when policies are designed to work only under particular
capacity or queuing policies. </dd>
<dt>Hook methods</dt>
这个类提供了(beforeExecute/afterExecute),在每个任务执行前后来调用。这些可以用来操纵执行环境,例如:重新启动 ThreadLocals,收集统计,或者添加日志事件。
额外,方法(terminated)可以被重写来处理那些特殊的,当Executor彻底中断的时候,需要被执行完毕的过程。
如果钩子或者回调方法抛出异常,内部的工作线程可能失败并突然中断。
<dd>This class provides {@code protected} overridable
{@link #beforeExecute(Thread, Runnable)} and
{@link #afterExecute(Runnable, Throwable)} methods that are called
before and after execution of each task. These can be used to
manipulate the execution environment; for example, reinitializing
ThreadLocals, gathering statistics, or adding log entries.
Additionally, method {@link #terminated} can be overridden to perform
any special processing that needs to be done once the Executor has
fully terminated.
<p>If hook or callback methods throw exceptions, internal worker
threads may in turn fail and abruptly terminate.</dd>
<dt>Queue maintenance</dt>
getQueue()方法允许访问工作线程,来监控和调试。不论任何目的,都强烈建议不要使用这个方法。
两个方法,remove()/purge(),当大量队列任务被取消的时候,能有效辅助存储空间的回收。
<dd>Method {@link #getQueue()} allows access to the work queue
for purposes of monitoring and debugging. Use of this method for
any other purpose is strongly discouraged. Two supplied methods,
{@link #remove(Runnable)} and {@link #purge} are available to
assist in storage reclamation when large numbers of queued tasks
become cancelled.</dd>
<dt>Finalization</dt>
不再被引用并且不再持有线程的线程池会被自动回收,如果你向确保无引用的池即使用户忘记调用 shutdown,也能回收,
那么你必须通过使用0核心线程的下限,并且/或者设置 allowCoreThreadTimeOut(),设置存活时间,来终止无用的线程。
<dd>A pool that is no longer referenced in a program <em>AND</em>
has no remaining threads will be {@code shutdown} automatically. If
you would like to ensure that unreferenced pools are reclaimed even
if users forget to call {@link #shutdown}, then you must arrange
that unused threads eventually die, by setting appropriate
keep-alive times, using a lower bound of zero core threads and/or
setting {@link #allowCoreThreadTimeOut(boolean)}. </dd>
</dl>
一个扩展的例子,这个类的大多数扩展都会覆盖一个或多个受保护的钩子方法。例如:
这个子类增加了一个简单的暂停/继续特性:
<p><b>Extension example</b>. Most extensions of this class
override one or more of the protected hook methods. For example,
here is a subclass that adds a simple pause/resume feature:
<pre> {@code
class PausableThreadPoolExecutor extends ThreadPoolExecutor {
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();
public PausableThreadPoolExecutor(...) { super(...); }
protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
pauseLock.lock();
try {
while (isPaused) unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
pauseLock.unlock();
}
}
public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}
public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}}</pre>
@since 1.5
@author Doug Lea
类简介略长,提炼信息如下:
线程池主要解决两个问题:处理大量任务时有更好的表现;提供很多可调节的参数以及扩展钩子,上下文切换更有用。
程序员更偏向使用:
Executors#newCachedThreadPool;不限制大小的线程池,并自动回收线程
Executors#newFixedThreadPool,固定大小的线程池
Executors#newSingleThreadExecutor,单个后台线程
ThreadPoolExecutor 会自动调整线程池大小 getPoolSize(),通过 corePoolSize getCorePoolSize() 和 maximumPoolSize getMaximumPoolSize();
当新任务通过 execute()提交时,并且运行的线程数量少于 corePoolSize,即使其他的线程是空闲的,也会创建一个新的线程来处理这个请求。如果运行的线程数量,大于 corePoolSize,
小于 maximumPoolSize,仅当队列满的时候,一个新得线程才会被创建(当队列不满的时候,会首先放入队列中)。
如果设置的 corePoolSize 等于 maximumPoolSize,会创建一个固定大小的线程池。
如果设置的 maximumPoolSize 无限大,比如等于 Integer.MAX_VALUE,允许无限多的任务并发处理。
典型的做法是,通过构造方法来设置 corePoolSize和 maximumPoolSize,但也可以通过 setCorePoolSize 和 setMaximumPoolSize 来动态设置。
看下execute()源码:
/**
* 在未来某时执行给定的任务。任务可以在新创建的线程,或者已经存在的线程中执行。
* 如果任务不能被提交执行,不论是因为executor已经关闭或者容量饱和,任务都会被当前 RejectedExecutionHandler 处理。
* Executes the given task sometime in the future. The task
* may execute in a new thread or in an existing pooled thread.
*
* If the task cannot be submitted for execution, either because this
* executor has been shutdown or because its capacity has been reached,
* the task is handled by the current {@code RejectedExecutionHandler}.
*
* @param command the task to execute
* @throws RejectedExecutionException at discretion of
* {@code RejectedExecutionHandler}, if the task
* cannot be accepted for execution
* @throws NullPointerException if {@code command} is null
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
* 处理分为3步:
* 1、如果少于 corePoolSize数量的线程在运行,尝试使用给定的command启动一个新的线程,作为它的第一个任务。调用方法 addWorker会自动检查 runState/workerCount.
* 2、如果一个线程成功入队,那么我们仍然需要双重检查(因为自动上一次检查,已经存在的一个已经死了),确定我们新增了一个线程,还是线程池自从进入了这个方法,已经
* 关闭了。因此我们重新检查状态,并在必要时回滚队列(如果已停止),或者在没有线程的情况下启动新线程。
* 3、如果我们不能入队新的任务,那么我们尝试新增一个线程,如果失败,我们知道我们已经关闭或者已经饱和,并拒绝任务。
*
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
int c = ctl.get(); // 首先看线程池的状态
if (workerCountOf(c) < corePoolSize) {// 线程数量小于定义的核心数
if (addWorker(command, true)) // 增加新的线程,并对任务进行处理
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) { //储与running状态,加入队列成功
int recheck = ctl.get(); // 重新检查
if (! isRunning(recheck) && remove(command))// 不是运行状态,并且删除任务成功
reject(command); // 执行拒绝策略
else if (workerCountOf(recheck) == 0) // 判断是否是shutdown
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
一般来说,只有任务到达的时候,核心线程才会被初始化创建,但是这可以通过 prestartCoreThread或者 prestartAllCoreThreads来动态重写。
当使用一个非空队列来创建的时候,可能想要预热一些线程
public boolean prestartCoreThread() {
return workerCountOf(ctl.get()) < corePoolSize &&
addWorker(null, true);
}
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))
++n;
return n;
}
属性:
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
持有一个原子整型,做为控制变量,该变量包含两部分:
workerCount:线程数,使用整型变量的低29位来表示。
runState:运行状态,使用整型的高位来表示,高3位。
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;
// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;
为了将两个变量整合到一个int中,限制了workerCount=(2^29)-1;如果以后不够用,也可以扩展为AtomicLong型,但是目前这种设计运算更快更简单。
runState 提供整个生命周期的控制,主要有以下几个值:
RUNNING:接受并处理任务
SHUTDOWN:不接受任务,但是处理任务
STOP:不接受任务,不处理任务,中断正在进行中的任务
TIDYING:中断所有任务,workerCount为0,线程状态为 TIDYING,即将运行 terminated()方法
TERMINATED:terminated()方法完成
状态随着时间变迁,但也不是所有的状态都会出现。迁移顺序为:
RUNNING->SHUTDOWN:可能在 finalize()中调用了 shutdown()
(RUNNING or SHUTDOWN) -> STOP:调用了 shutdownNow()
SHUTDOWN -> TIDYING:线程池和队列都会空
STOP -> TIDYING:线程池为空
TIDYING -> TERMINATED:terminated()钩子方法完成了调用
其他属性:
largestPoolSize:用来记录生命周期中线程池中,线程数量的最大值,该值只是一个记录,和corePollSize/maximumPollSize无关。
/**
* 记录线程池数量的最大值
* Tracks largest attained pool size. Accessed only under
* mainLock.
*/
private int largestPoolSize;
ThreadFactory threadFactory:线程工厂
/**
* 创建新线程的工厂。所有的线程都是经由这个工厂通过 addWorker()创建。调用可能会失败,可能会导致新增任务被拒绝,或者已存在的任务被卡。
* Factory for new threads. All threads are created using this
* factory (via method addWorker). All callers must be prepared
* for addWorker to fail, which may reflect a system or user's
* policy limiting the number of threads. Even though it is not
* treated as an error, failure to create threads may result in
* new tasks being rejected or existing ones remaining stuck in
* the queue.
*
* 尝试创建线程的时候,可能会抛出 OutOfMemoryError异常。一般都是因为 Thread.start 时期需要分配一个本地栈导致。并且用户想要清理线程池,这需要更多可用的内存空间。
* We go further and preserve pool invariants even in the face of
* errors such as OutOfMemoryError, that might be thrown while
* trying to create threads. Such errors are rather common due to
* the need to allocate a native stack in Thread.start, and users
* will want to perform clean pool shutdown to clean up. There
* will likely be enough memory available for the cleanup code to
* complete without encountering yet another OutOfMemoryError.
*/
private volatile ThreadFactory threadFactory;
RejectedExecutionHandler handler:拒绝处理策略
/**
* 饱和或者关闭
* Handler called when saturated or shutdown in execute.
*/
private volatile RejectedExecutionHandler handler;
long keepAliveTime:空闲线程的最大存活时间
/**
* 线程数量超过corePollSize时,空闲线程等待任务前的超时时间,除非指定allCoreThreadTimeOut,会一直等待新的任务
* Threads use this timeout when there are more than corePoolSize
* present or if allowCoreThreadTimeOut. Otherwise they wait
* forever for new work.
*/
private volatile long keepAliveTime;
是否允许线程超时: private volatile boolean allowCoreThreadTimeOut
/**
* 默认为false,核心线程一直存活,为true时,根据设置的存活时间keepAliveTime来设置超时时间
* If false (default), core threads stay alive even when idle.
* If true, core threads use keepAliveTime to time out waiting
* for work.
*/
private volatile boolean allowCoreThreadTimeOut;
int corePoolSize:最小存活线程数
/**
* 最小存活线程数量(不允许超时)除非设置了allowCoreThreadTimeOut,这种情况下最小数量为0
* Core pool size is the minimum number of workers to keep alive
* (and not allow to time out etc) unless allowCoreThreadTimeOut
* is set, in which case the minimum is zero.
*/
private volatile int corePoolSize;
int maximumPoolSize:线程池最大数量
/**
* 线程池最大数量,实际的最大数量受限于内部容量
* Maximum pool size. Note that the actual maximum is internally
* bounded by CAPACITY.
*/
private volatile int maximumPoolSize;
RejectedExecutionHandler defaultHandler = new AbortPolicy():默认的拒绝策略
/**
* 默认的拒绝执行者
* The default rejected execution handler
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
RuntimePermission shutdownPerm:关闭权限
/**
* 用户调用 shutdown/shutdownNow所需的权限。额外需要checkShutdownAccess检查调用者有权限去中断线程.
* 这些检查通过后 shutdown 才算完成。
*
* Permission required for callers of shutdown and shutdownNow.
* We additionally require (see checkShutdownAccess) that callers
* have permission to actually interrupt threads in the worker set
* (as governed by Thread.interrupt, which relies on
* ThreadGroup.checkAccess, which in turn relies on
* SecurityManager.checkAccess). Shutdowns are attempted only if
* these checks pass.
*
* 所有 Thread.interrupt忽略 SecurityException,意味中断尝试静默失败。
*
* All actual invocations of Thread.interrupt (see
* interruptIdleWorkers and interruptWorkers) ignore
* SecurityExceptions, meaning that the attempted interrupts
* silently fail. In the case of shutdown, they should not fail
* unless the SecurityManager has inconsistent policies, sometimes
* allowing access to a thread and sometimes not. In such cases,
* failure to actually interrupt threads may disable or delay full
* termination. Other uses of interruptIdleWorkers are advisory,
* and failure to actually interrupt will merely delay response to
* configuration changes so is not handled exceptionally.
*/
private static final RuntimePermission shutdownPerm =
new RuntimePermission("modifyThread");
/**
* If there is a security manager, makes sure caller has
* permission to shut down threads in general (see shutdownPerm).
* If this passes, additionally makes sure the caller is allowed
* to interrupt each worker thread. This might not be true even if
* first check passed, if the SecurityManager treats some threads
* specially.
*/
private void checkShutdownAccess() {
SecurityManager security = System.getSecurityManager();
if (security != null) {
security.checkPermission(shutdownPerm); // 判断是否有权限执行,判断逻辑后续再进行分析
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers)
security.checkAccess(w.thread);
} finally {
mainLock.unlock();
}
}
}
private final class Worker extends AbstractQueuedSynchronizer implements Runnable:新增任务处理线程时的内部类
构造方法,主要有四个:
// Public constructors and methods
// 构造方法,总共有4种,但是从源码中可以看出,前三种全部都是在调用第4种构造方法。
/**
* 使用初始化参数,默认线程工厂和拒绝策略处理器来创建一个新的线程。使用Executors工厂的一个或多个方法来替代这个构造方法可能会更方便。
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory and rejected execution handler.
* It may be more convenient to use one of the {@link Executors} factory
* methods instead of this general purpose constructor.
*
* 参数解析:
* corePoolSize:线程池中持有的线程数量,除非设置 allowCoreThreadTimeOut,可以空闲
* maximumPoolSize:线程池中允许的最大数量的线程数
* keepAliveTime:线程数量大于core,线程在中断前最长空闲时间
* unit:时间单元;NANOSECONDS ,MICROSECONDS ,MILLISECONDS ,SECONDS ,MINUTES ,HOURS ,DAYS
* workQueue:在任务执行前,保存任务的队列,这个队列只会保留通过execute()方法提交的Runable任务。
*
* @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.
* @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} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default rejected execution handler.
*
* @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
* @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} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters and default thread factory.
*
* @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 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 handler} is null
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
/**
* 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();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
主要方法:
addWorker():新增任务处理线程
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) {
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN &&
! (rs == SHUTDOWN &&
firstTask == null &&
! workQueue.isEmpty()))
return false;
for (;;) {
int wc = workerCountOf(c);
if (wc >= CAPACITY ||
wc >= (core ? corePoolSize : maximumPoolSize))
return false;
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
if (runStateOf(c) != rs)
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Recheck while holding lock.
// Back out on ThreadFactory failure or if
// shut down before lock acquired.
int rs = runStateOf(ctl.get());
if (rs < SHUTDOWN ||
(rs == SHUTDOWN && firstTask == null)) {
if (t.isAlive()) // precheck that t is startable
throw new IllegalThreadStateException();
workers.add(w);
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
workerAdded = true;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
shutdown():
/**
* 启动有序关闭,在该关闭中执行先前提交的任务,但不接受任何新任务。如果已经关闭,则调用不会产生任何其他影响。
* Initiates an orderly shutdown in which previously submitted
* tasks are executed, but no new tasks will be accepted.
* Invocation has no additional effect if already shut down.
*
* <p>This method does not wait for previously submitted tasks to
* complete execution. Use {@link #awaitTermination awaitTermination}
* to do that.
*
* @throws SecurityException {@inheritDoc}
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(SHUTDOWN);
interruptIdleWorkers();
onShutdown(); // hook for ScheduledThreadPoolExecutor
} finally {
mainLock.unlock();
}
tryTerminate();
}
shutdownNow():尝试关闭所有正在执行的任务
/**
*
* 尝试关闭所有正在执行的任务,停止处理过程中正在等待的任务,返回等待执行的任务列表。从此方法返回后,将从任务队列中清空(删除)这些任务。
* Attempts to stop all actively executing tasks, halts the
* processing of waiting tasks, and returns a list of the tasks
* that were awaiting execution. These tasks are drained (removed)
* from the task queue upon return from this method.
*
* 方法不会等待活动任务终止,使用 awaitTermination 去等待。
* <p>This method does not wait for actively executing tasks to
* terminate. Use {@link #awaitTermination awaitTermination} to
* do that.
*
*
* <p>There are no guarantees beyond best-effort attempts to stop
* processing actively executing tasks. This implementation
* cancels tasks via {@link Thread#interrupt}, so any task that
* fails to respond to interrupts may never terminate.
*
* @throws SecurityException {@inheritDoc}
*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
checkShutdownAccess();
advanceRunState(STOP);
interruptWorkers();
tasks = drainQueue();
} finally {
mainLock.unlock();
}
tryTerminate();
return tasks;
}
isTerminating() :
/**
* 如果执行器在执行 shutdown/shutdownNow之后,正在执行终止,但尚未完全终止,返回ture。
*
* Returns true if this executor is in the process of terminating
* after {@link #shutdown} or {@link #shutdownNow} but has not
* completely terminated. This method may be useful for
* debugging. A return of {@code true} reported a sufficient
* period after shutdown may indicate that submitted tasks have
* ignored or suppressed interruption, causing this executor not
* to properly terminate.
*
* @return {@code true} if terminating but not yet terminated
*/
public boolean isTerminating() {
int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
threadFactory的setter/getter方法:
/**
* Sets the thread factory used to create new threads.
*
* @param threadFactory the new thread factory
* @throws NullPointerException if threadFactory is null
* @see #getThreadFactory
*/
public void setThreadFactory(ThreadFactory threadFactory) {
if (threadFactory == null)
throw new NullPointerException();
this.threadFactory = threadFactory;
}
/**
* Returns the thread factory used to create new threads.
*
* @return the current thread factory
* @see #setThreadFactory(ThreadFactory)
*/
public ThreadFactory getThreadFactory() {
return threadFactory;
}
拒绝策略的setter/getter方法:
/**
* Sets a new handler for unexecutable tasks.
*
* @param handler the new handler
* @throws NullPointerException if handler is null
* @see #getRejectedExecutionHandler
*/
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
if (handler == null)
throw new NullPointerException();
this.handler = handler;
}
/**
* Returns the current handler for unexecutable tasks.
*
* @return the current handler
* @see #setRejectedExecutionHandler(RejectedExecutionHandler)
*/
public RejectedExecutionHandler getRejectedExecutionHandler() {
return handler;
}
setCorePollSize():核心数setter/getter方法:
/**
* Sets the core number of threads. This overrides any value set
* in the constructor. If the new value is smaller than the
* current value, excess existing threads will be terminated when
* they next become idle. If larger, new threads will, if needed,
* be started to execute any queued tasks.
*
* @param corePoolSize the new core size
* @throws IllegalArgumentException if {@code corePoolSize < 0}
* @see #getCorePoolSize
*/
public void setCorePoolSize(int corePoolSize) {
if (corePoolSize < 0)
throw new IllegalArgumentException();
int delta = corePoolSize - this.corePoolSize;
this.corePoolSize = corePoolSize;
if (workerCountOf(ctl.get()) > corePoolSize)
interruptIdleWorkers();
else if (delta > 0) {
// We don't really know how many new threads are "needed".
// As a heuristic, prestart enough new workers (up to new
// core size) to handle the current number of tasks in
// queue, but stop if queue becomes empty while doing so.
int k = Math.min(delta, workQueue.size());
while (k-- > 0 && addWorker(null, true)) {
if (workQueue.isEmpty())
break;
}
}
}
/**
* Returns the core number of threads.
*
* @return the core number of threads
* @see #setCorePoolSize
*/
public int getCorePoolSize() {
return corePoolSize;
}
超时机制的setter/getter:
public boolean allowsCoreThreadTimeOut() {
return allowCoreThreadTimeOut;
}
/**
* Sets the policy governing whether core threads may time out and
* terminate if no tasks arrive within the keep-alive time, being
* replaced if needed when new tasks arrive. When false, core
* threads are never terminated due to lack of incoming
* tasks. When true, the same keep-alive policy applying to
* non-core threads applies also to core threads. To avoid
* continual thread replacement, the keep-alive time must be
* greater than zero when setting {@code true}. This method
* should in general be called before the pool is actively used.
*
* @param value {@code true} if should time out, else {@code false}
* @throws IllegalArgumentException if value is {@code true}
* and the current keep-alive time is not greater than zero
*
* @since 1.6
*/
public void allowCoreThreadTimeOut(boolean value) {
if (value && keepAliveTime <= 0)
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
if (value != allowCoreThreadTimeOut) {
allowCoreThreadTimeOut = value;
if (value)
interruptIdleWorkers();
}
}
线程池最大数的setter/getter方法:
/**
* Sets the maximum allowed number of threads. This overrides any
* value set in the constructor. If the new value is smaller than
* the current value, excess existing threads will be
* terminated when they next become idle.
*
* @param maximumPoolSize the new maximum
* @throws IllegalArgumentException if the new maximum is
* less than or equal to zero, or
* less than the {@linkplain #getCorePoolSize core pool size}
* @see #getMaximumPoolSize
*/
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
throw new IllegalArgumentException();
this.maximumPoolSize = maximumPoolSize;
if (workerCountOf(ctl.get()) > maximumPoolSize)
interruptIdleWorkers();
}
/**
* Returns the maximum allowed number of threads.
*
* @return the maximum allowed number of threads
* @see #setMaximumPoolSize
*/
public int getMaximumPoolSize() {
return maximumPoolSize;
}
超时时间,keepAliveTime的setter/getter方法:
public void setKeepAliveTime(long time, TimeUnit unit) {
if (time < 0)
throw new IllegalArgumentException();
if (time == 0 && allowsCoreThreadTimeOut())
throw new IllegalArgumentException("Core threads must have nonzero keep alive times");
long keepAliveTime = unit.toNanos(time);
long delta = keepAliveTime - this.keepAliveTime;
this.keepAliveTime = keepAliveTime;
if (delta < 0)
interruptIdleWorkers();
}
/**
* Returns the thread keep-alive time, which is the amount of time
* that threads in excess of the core pool size may remain
* idle before being terminated.
*
* @param unit the desired time unit of the result
* @return the time limit
* @see #setKeepAliveTime(long, TimeUnit)
*/
public long getKeepAliveTime(TimeUnit unit) {
return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
}
remove(Runnable task):从队列中移除任务
/**
* 从队列中移除,如果还没有运行,那么就不会在运行了。
* Removes this task from the executor's internal queue if it is
* present, thus causing it not to be run if it has not already
* started.
*
* 在放入内部队列之前,可能无法删除已转换为其他状态的任务,例如,使用 submit 可能转换持有 Future 状态的表单,在这种情况下,可以使用 purge来删除已取消的Futures。
* <p>This method may be useful as one part of a cancellation
* scheme. It may fail to remove tasks that have been converted
* into other forms before being placed on the internal queue. For
* example, a task entered using {@code submit} might be
* converted into a form that maintains {@code Future} status.
* However, in such cases, method {@link #purge} may be used to
* remove those Futures that have been cancelled.
*
* @param task the task to remove
* @return {@code true} if the task was removed
*/
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
purge():
/**
* 尝试移除任务队列中所有被取消的Future任务,作为空间回收操作比较有用,对功能没有其他影响。取消的任务不再被执行,但是可能堆积在队列中,直到线程可以移除他们。
* 如果存在其他线程的干扰,这个方法可能会失败。
* Tries to remove from the work queue all {@link Future}
* tasks that have been cancelled. This method can be useful as a
* storage reclamation operation, that has no other impact on
* functionality. Cancelled tasks are never executed, but may
* accumulate in work queues until worker threads can actively
* remove them. Invoking this method instead tries to remove them now.
* However, this method may fail to remove tasks in
* the presence of interference by other threads.
*/
public void purge() {
final BlockingQueue<Runnable> q = workQueue;
try {
Iterator<Runnable> it = q.iterator();
while (it.hasNext()) {
Runnable r = it.next();
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
it.remove();
}
} catch (ConcurrentModificationException fallThrough) {
// Take slow path if we encounter interference during traversal.
// Make copy for traversal and call remove for cancelled entries.
// The slow path is more likely to be O(N*N).
for (Object r : q.toArray())
if (r instanceof Future<?> && ((Future<?>)r).isCancelled())
q.remove(r);
}
tryTerminate(); // In case SHUTDOWN and now empty
}
对ThreadPoolSize进行的扩展,主要是通过三个钩子方法:
protected void beforeExecute(Thread t, Runnable r) { }
protected void afterExecute(Runnable r, Throwable t) { }
protected void terminated() { }
/**
* 任务线程执行前的前置处理,可以用来初始化或者日志记录。是一个空实现,在子类中可以进行定制化处理,需要在方法最后调用 super.beforeExecute.
* Method invoked prior to executing the given Runnable in the
* given thread. This method is invoked by thread {@code t} that
* will execute task {@code r}, and may be used to re-initialize
* ThreadLocals, or to perform logging.
*
* <p>This implementation does nothing, but may be customized in
* subclasses. Note: To properly nest multiple overridings, subclasses
* should generally invoke {@code super.beforeExecute} at the end of
* this method.
*
* @param t the thread that will run task {@code r}
* @param r the task that will be executed
*/
protected void beforeExecute(Thread t, Runnable r) { }
/**
* Method invoked upon completion of execution of the given Runnable.
* This method is invoked by the thread that executed the task. If
* non-null, the Throwable is the uncaught {@code RuntimeException}
* or {@code Error} that caused execution to terminate abruptly.
*
* 方法开始调用父类方法:super.afterExecute.
* <p>This implementation does nothing, but may be customized in
* subclasses. Note: To properly nest multiple overridings, subclasses
* should generally invoke {@code super.afterExecute} at the
* beginning of this method.
*
* <p><b>Note:</b> When actions are enclosed in tasks (such as
* {@link FutureTask}) either explicitly or via methods such as
* {@code submit}, these task objects catch and maintain
* computational exceptions, and so they do not cause abrupt
* termination, and the internal exceptions are <em>not</em>
* passed to this method. If you would like to trap both kinds of
* failures in this method, you can further probe for such cases,
* as in this sample subclass that prints either the direct cause
* or the underlying exception if a task has been aborted:
*
* <pre> {@code
* class ExtendedExecutor extends ThreadPoolExecutor {
* // ...
* protected void afterExecute(Runnable r, Throwable t) {
* super.afterExecute(r, t);
* if (t == null && r instanceof Future<?>) {
* try {
* Object result = ((Future<?>) r).get();
* } catch (CancellationException ce) {
* t = ce;
* } catch (ExecutionException ee) {
* t = ee.getCause();
* } catch (InterruptedException ie) {
* Thread.currentThread().interrupt(); // ignore/reset
* }
* }
* if (t != null)
* System.out.println(t);
* }
* }}</pre>
*
* @param r the runnable that has completed
* @param t the exception that caused termination, or null if
* execution completed normally
*/
protected void afterExecute(Runnable r, Throwable t) { }
/**
* 当 Executors被中断时调用的方法,默认什么都不做.子类重写方法体中,需要调用 super.terminated;
* Method invoked when the Executor has terminated. Default
* implementation does nothing. Note: To properly nest multiple
* overridings, subclasses should generally invoke
* {@code super.terminated} within this method.
*/
protected void terminated() { }
拒绝策略,根据类简介中介绍,拒绝策略默认实现总共有4种,如下:也可以自定义拒绝策略:
/**
* A handler for rejected tasks that runs the rejected task
* directly in the calling thread of the {@code execute} method,
* unless the executor has been shut down, in which case the task
* is discarded.
*/
public static class CallerRunsPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code CallerRunsPolicy}.
*/
public CallerRunsPolicy() { }
/**
* Executes task r in the caller's thread, unless the executor
* has been shut down, in which case the task is discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
/**
* A handler for rejected tasks that throws a
* {@code RejectedExecutionException}.
*/
public static class AbortPolicy implements RejectedExecutionHandler {
/**
* Creates an {@code AbortPolicy}.
*/
public AbortPolicy() { }
/**
* Always throws RejectedExecutionException.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
* @throws RejectedExecutionException always
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
throw new RejectedExecutionException("Task " + r.toString() +
" rejected from " +
e.toString());
}
}
/**
* A handler for rejected tasks that silently discards the
* rejected task.
*/
public static class DiscardPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardPolicy}.
*/
public DiscardPolicy() { }
/**
* Does nothing, which has the effect of discarding task r.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
/**
* A handler for rejected tasks that discards the oldest unhandled
* request and then retries {@code execute}, unless the executor
* is shut down, in which case the task is discarded.
*/
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
/**
* Creates a {@code DiscardOldestPolicy} for the given executor.
*/
public DiscardOldestPolicy() { }
/**
* Obtains and ignores the next task that the executor
* would otherwise execute, if one is immediately available,
* and then retries execution of task r, unless the executor
* is shut down, in which case task r is instead discarded.
*
* @param r the runnable task requested to be executed
* @param e the executor attempting to execute this task
*/
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}