线程池
ThreadPoolExecutor
池化技术:便于管理和回收线程,可以进行重复利用,减少创建和回收线程的开销
源码
Executor
public interface Executor {
/**
* 在将来的某个时间执行给定的命令。该命令可以在 新线程、线程池 或 调用线程中执行,具体取决于Executor实现
*/
void execute(Runnable command); //定义提交的任务
}
ExecutorService
public interface ExecutorService extends Executor {
/**
* 启动有序关闭,继续执行先前提交的任务,但不会接受新任务。如果已经关闭,调用不会产生额外的效果。
* 该方法不等待之前提交的任务完成执行。使用awaitTermination来做到这一点
*/
void shutdown();
/**
* 尝试停止所有正在执行的任务,停止正在等待的任务的处理,并返回正在等待执行的任务的列表。
* 此方法不等待主动执行的任务终止。使用awaitTermination来做到这一点。
* 除了尽最大努力尝试停止处理主动执行的任务之外,没有任何保证。
* 例如,典型的实现将通过Thread.interrupt取消,因此任何无法响应中断的任务可能永远不会终止。
*/
List<Runnable> shutdownNow();
/**
* 如果此执行器已关闭,则返回true
*/
boolean isShutdown();
/**
* 如果关闭后所有任务均已完成,则返回true 。请注意,除非首先调用shutdown或shutdownNow否则isTerminated永远不会为true 。
*/
boolean isTerminated();
/**
* 阻塞,直到所有任务在关闭请求后完成执行,或者发生超时,或者当前线程被中断,以先发生者为准。
*/
boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;
/**
* 提交一个返回值的任务来执行,并返回一个表示任务待处理结果的 Future。
* Future 的get方法将在成功完成后返回任务的结果。
* 如果您想立即阻止等待任务,可以使用result = exec.submit(aCallable).get();
*/
<T> Future<T> submit(Callable<T> task);
/**
* 提交一个 Runnable 任务来执行并返回一个表示该任务的 Future。 Future 的get方法将在成功完成后返回 给定的结果。
*/
<T> Future<T> submit(Runnable task, T result);
/**
* 提交一个 Runnable 任务来执行并返回一个表示该任务的 Future。 Future 的get方法在成功完成后将返回 null 。
*/
Future<?> submit(Runnable task);
/**
* 执行给定的任务,在全部完成时返回保存其状态和结果的 Future 列表。对于返回列表中的每个元素, Future.isDone都为true 。
* 请注意,已完成的任务可能会正常终止或通过引发异常终止。如果在此操作进行期间修改给定集合,则此方法的结果是未定义的。
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)throws InterruptedException;
/**
* 执行给定的任务,当所有任务完成或超时到期(以先发生者为准)时,返回保存其状态和结果的 Future 列表。
* 对于返回列表中的每个元素, Future.isDone都为true 。返回后,未完成的任务将被取消。
* 请注意,已完成的任务可能会正常终止或通过引发异常终止。如果在此操作进行期间修改给定集合,则此方法的结果是未定义的。
*/
<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException;
/**
* 执行给定的任务,返回已成功完成的任务的结果(即,不引发异常)(如果有)。
* 正常或异常返回时,未完成的任务将被取消。如果在此操作进行期间修改给定集合,则此方法的结果是未定义的
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException;
/**
* 执行给定的任务,返回已成功完成的任务的结果(即,不引发异常)(如果在给定超时之前有任何执行)。
* 正常或异常返回时,未完成的任务将被取消。如果在此操作进行期间修改给定集合,则此方法的结果是未定义的
*/
<T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}
AbstractExecutorService
package java.util.concurrent;
import java.util.*;
/**
* 提供ExecutorService执行方法的默认实现。
* 该类使用newTaskFor返回的RunnableFuture实现了submit 、 invokeAny和invokeAll方法,默认为该包中提供的FutureTask类。
* 例如submit(Runnable)的实现创建一个执行并返回的关联RunnableFuture 。子类可以重写newTaskFor方法以返回除FutureTask之外的RunnableFuture实现。
*/
public abstract class AbstractExecutorService implements ExecutorService {
/**
* 返回给定可运行对象和默认值的RunnableFuture
*/
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
/**
* 返回给定可调用任务的RunnableFuture 。
*/
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new FutureTask<T>(callable);
}
【任务在线程池中的执行入口: submit() execute() 】
/**
* RejectedExecutionException – 如果无法安排任务执行 NullPointerException – 如果任务为 null
*/
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
//封装任务
RunnableFuture<Void> ftask = newTaskFor(task, null);
//执行任务
execute(ftask);
//返回 Future
return ftask;
}
/**
* RejectedExecutionException – 如果无法安排任务执行 NullPointerException – 如果任务为 null
*/
public <T> Future<T> submit(Runnable task, T result) {
if (task == null) throw new NullPointerException();
//封装任务
RunnableFuture<T> ftask = newTaskFor(task, result);
//执行任务
execute(ftask);
//返回 Future
return ftask;
}
/**
* RejectedExecutionException – 如果无法安排任务执行 NullPointerException – 如果任务为 null
*/
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
/**
* the main mechanics of invokeAny.
*/
private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks,
boolean timed, long nanos)
throws InterruptedException, ExecutionException, TimeoutException {
if (tasks == null)
throw new NullPointerException();
int ntasks = tasks.size();
if (ntasks == 0)
throw new IllegalArgumentException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(ntasks);
ExecutorCompletionService<T> ecs = new ExecutorCompletionService<T>(this);
// For efficiency, especially in executors with limited
// parallelism, check to see if previously submitted tasks are
// done before submitting more of them. This interleaving
// plus the exception mechanics account for messiness of main
// loop.
try {
// Record exceptions so that if we fail to obtain any
// result, we can throw the last exception we got.
ExecutionException ee = null;
final long deadline = timed ? System.nanoTime() + nanos : 0L;
Iterator<? extends Callable<T>> it = tasks.iterator();
// Start one task for sure; the rest incrementally
futures.add(ecs.submit(it.next()));
--ntasks;
int active = 1;
for (;;) {
Future<T> f = ecs.poll();
if (f == null) {
if (ntasks > 0) {
--ntasks;
futures.add(ecs.submit(it.next()));
++active;
}
else if (active == 0)
break;
else if (timed) {
f = ecs.poll(nanos, TimeUnit.NANOSECONDS);
if (f == null)
throw new TimeoutException();
nanos = deadline - System.nanoTime();
}
else
f = ecs.take();
}
if (f != null) {
--active;
try {
return f.get();
} catch (ExecutionException eex) {
ee = eex;
} catch (RuntimeException rex) {
ee = new ExecutionException(rex);
}
}
}
if (ee == null)
ee = new ExecutionException();
throw ee;
} finally {
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks)
throws InterruptedException, ExecutionException {
try {
return doInvokeAny(tasks, false, 0);
} catch (TimeoutException cannotHappen) {
assert false;
return null;
}
}
public <T> T invokeAny(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
return doInvokeAny(tasks, true, unit.toNanos(timeout));
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (int i = 0, size = futures.size(); i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
try {
f.get();
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks,
long timeout, TimeUnit unit)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
long nanos = unit.toNanos(timeout);
ArrayList<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks)
futures.add(newTaskFor(t));
final long deadline = System.nanoTime() + nanos;
final int size = futures.size();
// Interleave time checks and calls to execute in case
// executor doesn't have any/much parallelism.
for (int i = 0; i < size; i++) {
execute((Runnable)futures.get(i));
nanos = deadline - System.nanoTime();
if (nanos <= 0L)
return futures;
}
for (int i = 0; i < size; i++) {
Future<T> f = futures.get(i);
if (!f.isDone()) {
if (nanos <= 0L)
return futures;
try {
f.get(nanos, TimeUnit.NANOSECONDS);
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
} catch (TimeoutException toe) {
return futures;
}
nanos = deadline - System.nanoTime();
}
}
done = true;
return futures;
} finally {
if (!done)
for (int i = 0, size = futures.size(); i < size; i++)
futures.get(i).cancel(true);
}
}
}
ThreadPoolExecutor
线程的状态
package java.util.concurrent;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.*;
/**
*ExecutorService使用可能的多个池线程之一执行每个提交的任务,通常使用Executors工厂方法进行配置。
线程池解决了两个不同的问题:
1、由于减少了每个任务的调用开销,它们通常在执行大量异步任务时提供改进的性能,
2、它们提供了一种限制和管理资源的方法,包括执行一组异步任务时消耗的线程。任务。每个ThreadPoolExecutor还维护一些基本统计数据,例如已完成任务的数量。
为了在广泛的上下文中发挥作用,此类提供了许多可调整的参数和可扩展性挂钩。但是,建议程序员使用更方便的Executors工厂方法Executors.newCachedThreadPool (无界线程池,具有自动线程回收功能)、 Executors.newFixedThreadPool (固定大小线程池)和Executors.newSingleThreadExecutor (单后台线程),这些方法可以预先配置设置最常见的使用场景。
否则,请在手动配置和调整此类时使用以下指南:
按需施工
默认情况下,即使是核心线程也仅在新任务到达时才最初创建和启动,但这可以使用方法prestartCoreThread或prestartAllCoreThreads动态覆盖。如果您使用非空队列构造池,您可能需要预启动线程。
存活次数
如果池当前拥有超过 corePoolSize 的线程,则多余的线程如果空闲时间超过 keepAliveTime,将被终止。
这提供了一种在池未被积极使用时减少资源消耗的方法。
如果池稍后变得更加活跃,则会构造新线程。还可以使用方法setKeepAliveTime(long, TimeUnit)动态更改此参数。
使用Long.MAX_VALUE TimeUnit.NANOSECONDS值可以有效地禁止空闲线程在关闭之前终止。默认情况下,仅当线程数超过 corePoolSize 时才应用保持活动策略
但是,只要 keepAliveTime 值非零,也可以使用方法allowCoreThreadTimeOut(boolean)将此超时策略应用于核心线程。
钩子方法
此类提供protected可重写beforeExecute(Thread, Runnable)和afterExecute(Runnable, Throwable)方法,这些方法在每个任务执行之前和之后调用。这些可用于操纵执行环境;例如,重新初始化 ThreadLocals、收集统计信息或添加日志条目。此外,一旦执行器完全terminated方法来执行需要完成的任何特殊处理。
如果钩子或回调方法抛出异常,内部工作线程可能会失败并突然终止。
队列维护
方法getQueue()允许访问工作队列以进行监视和调试。强烈建议不要将此方法用于任何其他目的。当大量排队任务被取消时, remove(Runnable)和purge这两个提供的方法可用于协助存储回收
最终确定
程序中不再引用且没有剩余线程的池 将自动shutdown 。
如果您想确保即使用户忘记调用shutdown也能回收未引用的池,那么您必须通过设置适当的保持活动时间、使用零核心线程的下限和/或设置allowCoreThreadTimeOut(boolean)来安排未使用的线程最终死亡allowCoreThreadTimeOut(boolean) 。
扩展示例:
此类的大多数扩展都会重写一个或多个受保护的挂钩方法。例如,这是一个添加简单暂停/恢复功能的子类:
* 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();
* }
* }
* }
}
*/
public class ThreadPoolExecutor extends AbstractExecutorService {
/**
* 主池控制状态 ctl 是一个原子整数,
包装了 两个概念字段
workerCount,表示线程的有效数量
runState,表示是否正在运行,关闭等状态;为了将它们包装成一个int,我们将workerCount限制为(2^29 )-1(约 5 亿)个线程,而不是 (2^31)-1(20 亿)个线程。
如果将来出现这个问题,可以将该变量更改为 AtomicLong,并调整下面的移位/掩码常量。但在需要之前,使用 int 的代码会更快、更简单。
workerCount 是已允许启动且不允许停止的工作线程数。
该值可能会暂时不同于活动线程的实际数量,例如,当 ThreadFactory 在被请求时无法创建线程时,以及退出线程在终止之前仍在执行时。
用户可见的池大小被报告为工作集的当前大小。
runState 提供主要的生命周期控制,取值如下:
RUNNING:接受新任务并处理排队任务
SHUTDOWN:不接受新任务,但处理排队任务
STOP:不接受新任务,不处理排队任务,并中断正在进行的任务
TIDYING:所有任务都已终止, workerCount 为零,线程转换到状态 TIDYING 将运行 terminated() 钩子方法
TERMINATED:终止()已完成
这些值之间的数字顺序很重要,以允许有序比较。 runState 随着时间的推移单调增加,但不需要达到每个状态。
转换为:
RUNNING -> SHUTDOWN 在调用 shutdown() 时,可能隐式地在 Finalize() 中
(RUNNING 或 SHUTDOWN) -> STOP 在调用 shutdownNow() 时
SHUTDOWN -> TIDYING 当队列和池都为空时
STOP -> TIDYING当池为空时
TIDYING -> TERMINATED 当terminated() 钩子方法完成时
在awaitTermination()中等待的线程将在状态达到TERMINATED时返回。
检测从 SHUTDOWN 到 TIDYING 的转换并不像您想象的那么简单,因为队列在非空后可能会变空,在 SHUTDOWN 状态期间反之亦然,只有当我们看到它是空的之后,我们才发现workerCount是0,我们才能终止(有时需要重新检查下文)。
*/
// ctl 的高 3 位 表示线程池的 状态, 低29位表示线程池中正在运行的线程个数
private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3; // 32-3 = 29位的常量
// 0001 1111 1111 1111 1111 1111 1111 1111
private static final int CAPACITY = (1 << COUNT_BITS) - 1; // 1左移29位 - 1 , 约5亿,最大的线程数
// runState is stored in the high-order bits
// RUNNING < SHUTDOWN < STOP < TIDYING < TERMINATED
//1010 0000 0000 0000 0000 0000 0000 0000
private static final int RUNNING = -1 << COUNT_BITS; // RUNNING 正在运行,接受新任务并处理 排队任务
//0000 0000 0000 0000 0000 0000 0000 0000
private static final int SHUTDOWN = 0 << COUNT_BITS; // SHUTDOWN 线程池不接受任务 但是队列中的任务可以继续执行
//0010 0000 0000 0000 0000 0000 0000 0000
private static final int STOP = 1 << COUNT_BITS; // STOP 线程池不接受任务 不处理排队任务 且中断正在处理的任务
//0100 0000 0000 0000 0000 0000 0000 0000
private static final int TIDYING = 2 << COUNT_BITS; // TIDYING 状态下会触发钩子函数terminated(),默认是个空函数,可以重写实现逻辑
// 当所有的任务已终止,workerCount数量为 0 ,线程池会变为 TIDYING 状态
// SHUTDOWN 状态的线程池,当所有任务都执行完时,线程池会变为 TIDYING 状态
// STOP 状态的线程池,当所有正在执行任务都终止,线程池会变为 TIDYING 状态
//0110 0000 0000 0000 0000 0000 0000 0000
private static final int TERMINATED = 3 << COUNT_BITS; // TERMINATED 线程池结束,所有钩子方法【需要用户实现的方法】也执行结束
//TIDYING 状态下的线程池,回调钩子函数 terminated() 时,状态由此变成 TERMINATED
/* 0110 0000 0000 0000 0000 0000 0000 0000/...(c)
* & 1110 0000 0000 0000 0000 0000 0000 0000 = (~(0001 1111 1111 1111 1111 1111 1111 1111))
* = 0110 0000 0000 0000 0000 0000 0000 0000
*/
private static int runStateOf(int c) { return c & ~CAPACITY; } // 获取线程池的状态
private static int workerCountOf(int c) { return c & CAPACITY; } // 获取线程池正在运行的线程个数
private static int ctlOf(int rs, int wc) { return rs | wc; } // 将线程的最高3位 和 低29位 组合成 一个 int 数,就是 ctl 值
/*
* Bit field accessors that don't require unpacking ctl.
* These depend on the bit layout and on workerCount being never negative.
*/
private static boolean runStateLessThan(int c, int s) { return c < s;}
private static boolean runStateAtLeast(int c, int s) { return c >= s; }
private static boolean isRunning(int c) { return c < SHUTDOWN; }
/**
* Attempts to CAS-increment the workerCount field of ctl.
*/
private boolean compareAndIncrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect + 1); }
/**
* Attempts to CAS-decrement the workerCount field of ctl.
*/
private boolean compareAndDecrementWorkerCount(int expect) { return ctl.compareAndSet(expect, expect - 1); }
/**
* 减少 ctl 的 workerCount 字段。仅在线程突然终止时才调用此函数。其他递减在 getTask 中执行。
*/
private void decrementWorkerCount() { do {} while (! compareAndDecrementWorkerCount(ctl.get())); }
/**
* 队列用于保存任务并移交给工作线程。
*/
private final BlockingQueue<Runnable> workQueue;
/**
* 锁
*/
private final ReentrantLock mainLock = new ReentrantLock();
/**
* 包含池中所有工作线程的集合。仅当持有 mainLock 时才可访问。
*/
private final HashSet<Worker> workers = new HashSet<Worker>();
/**
* 支持awaitTermination的等待条件
*/
private final Condition termination = mainLock.newCondition();
/**
* Tracks largest attained pool size. Accessed only under mainLock.
*/
private int largestPoolSize;
/**
* Counter for completed tasks. Updated only on termination of
* worker threads. Accessed only under mainLock.
*/
private long completedTaskCount; //线程池完成的任务个数
/*
* 所有用户控制参数都声明为易失性,以便正在进行的操作基于最新值,但不需要锁定,因为没有内部不变量依赖于它们相对于其他操作同步更改。
*/
/**
* 新线程工厂
*/
private volatile ThreadFactory threadFactory; // 线程工厂
/**
* 处理程序在执行中饱和或关闭时调用
*/
private volatile RejectedExecutionHandler handler; // 拒绝策略
/**
* 等待工作的空闲线程的超时(以纳秒为单位)。当存在的线程数量超过 corePoolSize 或允许CoreThreadTimeOut 时,线程将使用此超时。
* 否则他们将永远等待新工作
*/
private volatile long keepAliveTime; // 要多久还拿不到任务 就线程销毁
/**
* 如果为 false(默认),核心线程即使在空闲时也保持活动(存活、不销毁)态。
* 如果为 true,则核心线程使用 keepAliveTime 来超时等待工作。
*/
private volatile boolean allowCoreThreadTimeOut; // 核心线程是不是要销毁(默认false,不销毁)
/**
* 核心池大小是保持活动状态的最小工作线程数(并且不允许超时等),除非设置了allowCoreThreadTimeOut,在这种情况下最小值为零。
*/
private volatile int corePoolSize;
/**
* 最大池大小。请注意,实际最大值在内部受容量限制。
*/
private volatile int maximumPoolSize;
/**
* 默认拒绝执行处理程序
*/
private static final RejectedExecutionHandler defaultHandler =
new AbortPolicy();
/**
* shutdown 和 shutdownNow 调用者需要Permission。
*/
private static final RuntimePermission shutdownPerm = new RuntimePermission("modifyThread");
/* 执行 finalizer 时要使用的上下文,或者为 null。 */
private final AccessControlContext acc;
/*
构造函数
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
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;
}
// 一些 set get 的方法
public void setThreadFactory(ThreadFactory threadFactory) {
if (threadFactory == null)
throw new NullPointerException();
this.threadFactory = threadFactory;
}
public ThreadFactory getThreadFactory() {
return threadFactory;
}
public void setRejectedExecutionHandler(RejectedExecutionHandler handler) {
if (handler == null)
throw new NullPointerException();
this.handler = handler;
}
public RejectedExecutionHandler getRejectedExecutionHandler() {
return handler;
}
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) {
int k = Math.min(delta, workQueue.size());
while (k-- > 0 && addWorker(null, true)) {
if (workQueue.isEmpty())
break;
}
}
}
public int getCorePoolSize() {
return corePoolSize;
}
public boolean prestartCoreThread() {
return workerCountOf(ctl.get()) < corePoolSize &&
addWorker(null, true);
}
void ensurePrestart() {
int wc = workerCountOf(ctl.get());
if (wc < corePoolSize)
addWorker(null, true);
else if (wc == 0)
addWorker(null, false);
}
public int prestartAllCoreThreads() {
int n = 0;
while (addWorker(null, true))
++n;
return n;
}
public boolean allowsCoreThreadTimeOut() {
return allowCoreThreadTimeOut;
}
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();
}
}
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
throw new IllegalArgumentException();
this.maximumPoolSize = maximumPoolSize;
if (workerCountOf(ctl.get()) > maximumPoolSize)
interruptIdleWorkers();
}
public int getMaximumPoolSize() {
return maximumPoolSize;
}
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();
}
public long getKeepAliveTime(TimeUnit unit) {
return unit.convert(keepAliveTime, TimeUnit.NANOSECONDS);
}
public BlockingQueue<Runnable> getQueue() {
return workQueue;
}
public boolean remove(Runnable task) {
boolean removed = workQueue.remove(task);
tryTerminate(); // In case SHUTDOWN and now empty
return removed;
}
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
}
public int getPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// Remove rare and surprising possibility of
// isTerminated() && getPoolSize() > 0
return runStateAtLeast(ctl.get(), TIDYING) ? 0
: workers.size();
} finally {
mainLock.unlock();
}
}
public int getActiveCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int n = 0;
for (Worker w : workers)
if (w.isLocked())
++n;
return n;
} finally {
mainLock.unlock();
}
}
public int getLargestPoolSize() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
return largestPoolSize;
} finally {
mainLock.unlock();
}
}
public long getTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers) {
n += w.completedTasks;
if (w.isLocked())
++n;
}
return n + workQueue.size();
} finally {
mainLock.unlock();
}
}
public long getCompletedTaskCount() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
long n = completedTaskCount;
for (Worker w : workers)
n += w.completedTasks;
return n;
} finally {
mainLock.unlock();
}
}
public String toString() {
long ncompleted;
int nworkers, nactive;
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
ncompleted = completedTaskCount;
nactive = 0;
nworkers = workers.size();
for (Worker w : workers) {
ncompleted += w.completedTasks;
if (w.isLocked())
++nactive;
}
} finally {
mainLock.unlock();
}
int c = ctl.get();
String rs = (runStateLessThan(c, SHUTDOWN) ? "Running" :
(runStateAtLeast(c, TERMINATED) ? "Terminated" :
"Shutting down"));
return super.toString() +
"[" + rs +
", pool size = " + nworkers +
", active threads = " + nactive +
", queued tasks = " + workQueue.size() +
", completed tasks = " + ncompleted +
"]";
}
/* Extension hooks */
protected void beforeExecute(Thread t, Runnable r) { }
protected void afterExecute(Runnable r, Throwable t) { }
protected void terminated() { }
// 拒绝策略 内部类
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
r.run();
}
}
}
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());
}
}
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
}
}
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
}
理论知识
-
核心和最大池大小:ThreadPoolExecutor将根据 corePoolSize 和 MaximumPoolSize 设置的边界自动调整池大小。
- 当在方法execute(Runnable)中提交 新任务并且 运行的线程 少于corePoolSize时,即使 其他工作线程处于空闲状态,会创建一个新线程来处理该请求。
- 如果运行的线程数大于 corePoolSize 但小于 maxPoolSize,则仅当队列已满时 才会创建新线程。
- 通过将 corePoolSize 和 MaximumPoolSize 设置为相同,可以创建固定大小的线程池。通过将 MaximumPoolSize 设置为本质上无界的值(例如Integer.MAX_VALUE ,可以允许池容纳任意数量的并发任务。
- 最典型的是,核心和最大池大小仅在构造时设置,但也可以使用setCorePoolSize和setMaximumPoolSize动态更改。
-
创建新线程
新线程是使用ThreadFactory创建的。如果没有另外指定,则使用 默认的线程工厂 ,它创建的线程都位于同一 ThreadGroup 中,并具有相同的NORM_PRIORITY优先级和非守护进程状态。通过提供不同的 ThreadFactory,您可以更改线程的名称、线程组、优先级、守护进程状态等。- 如果ThreadFactory在通过从newThread返回 null 表示未能创建线程,则执行程序将继续,但可能无法执行任何任务。
- 线程应该拥有“modifyThread” RuntimePermission 。如果工作线程或使用该池的其他线程不拥有此权限,则服务可能会降级:配置更改可能无法及时生效,并且关闭池可能仍处于可能终止但未完成的状态。
-
队列
-
任何BlockingQueue都可用于传输和保存已提交的任务。该队列的使用与池大小相互作用:
- 如果运行的线程少于 corePoolSize,则 Executor 始终倾向于添加新线程而不是排队。
- 如果 corePoolSize 或更多线程正在运行,Executor 总是更喜欢对请求进行排队而不是添加新线程。
- 如果请求无法排队,则会创建一个新线程,除非这超出了 MaximumPoolSize,在这种情况下,该任务将被拒绝。
-
排队的一般策略有以下三种:
-
直接切换。工作队列的一个不错的默认选择是 SynchronousQueue ,它将任务交给线程而不以其他方式保留它们。在这里,如果没有线程可以立即运行任务,则尝试对任务进行排队将会失败,因此将构造一个新线程。
此策略可避免在处理可能具有内部依赖性的请求集时发生锁定。
直接切换通常需要无限制的 MaximumPoolSizes 以避免拒绝新提交的任务。
这反过来又承认当命令到达的平均速度继续快于处理速度时,线程可能会无限增长。
-
无界队列。当所有 corePoolSize 线程都忙时,使用无界队列(例如没有预定义容量的LinkedBlockingQueue )将导致新任务在队列中等待。因此,将不会创建超过 corePoolSize 的线程。 (因此,maximumPoolSize 的值不会产生任何影响。)当每个任务完全独立于其他任务时,这可能是合适的,因此任务不会影响彼此的执行;例如,在网页服务器中。虽然这种排队方式对于平滑请求的瞬时突发很有用,但它承认当命令平均到达速度继续快于处理速度时,工作队列可能会无限增长。
-
有界队列。有界队列(例如ArrayBlockingQueue )在与有限的 MaximumPoolSizes 一起使用时有助于防止资源耗尽,但可能更难以调整和控制。队列大小和最大池大小可以相互权衡:使用大队列和小池可以最大限度地减少 CPU 使用率、操作系统资源和上下文切换开销,但可能会导致人为降低吞吐量。如果任务经常阻塞(例如,如果它们受 I/O 限制),系统可能会为比您允许的更多线程安排时间。使用小队列通常需要更大的池大小,这会使 CPU 更加繁忙,但可能会遇到不可接受的调度开销,这也会降低吞吐量
-
-
-
任务的拒接策略:当 Executor 关闭时,以及当 Executor 对最大线程和工作队列容量使用有限界限并且饱和时,在方法execute(Runnable)中提交的新任务将被拒绝。无论哪种情况, execute方法都会调用其RejectedExecutionHandler的RejectedExecutionHandler.rejectedExecution(Runnable, ThreadPoolExecutor)方法。提供了四种预定义的处理程序策略:
-
在默认的ThreadPoolExecutor.AbortPolicy中,处理程序在拒绝时抛出运行时RejectedExecutionException 。
-
在ThreadPoolExecutor.CallerRunsPolicy中,调用execute本身的线程运行任务。这提供了一个简单的反馈控制机制,将减慢新任务提交的速度。
-
在ThreadPoolExecutor.DiscardPolicy中,无法执行的任务将被简单地丢弃。
-
在ThreadPoolExecutor.DiscardOldestPolicy中,如果执行器没有关闭,则工作队列头部的任务将被丢弃,然后重试执行(可能会再次失败,导致重复执行)。
-
线程池执行流程
execute
/**
在将来的某个时间执行给定的任务。
该任务可以在新线程或现有池线程中执行。
如果任务无法提交执行,无论是因为该执行器已关闭还是因为其容量已达到,则该任务将由当前的RejectedExecutionHandler处理
*/
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
* 1.如果正在运行的线程少于 corePoolSize,请尝试使用给定命令启动一个新线程作为其第一个任务。
对 addWorker 的调用以原子方式检查 runState 和workerCount,从而通过返回 false 来防止在不应该添加线程时添加线程的错误警报。
* 2.如果任务可以成功排队,那么我们仍然需要仔细检查是否应该添加线程(因为自上次检查以来现有线程已死亡),或者自进入此方法以来池已关闭
因此,我们重新检查状态,并在必要时回滚排队(如果停止),或者启动一个新线程(如果没有)。
* 3.如果我们无法将任务排队,那么我们尝试添加一个新线程。如果失败,我们就知道我们已关闭或饱和,因此拒绝该任务。
*/
int c = ctl.get();
// 1
if (workerCountOf(c) < corePoolSize) { // workerCountOf(c) 计算线程池的工作线程数 < 核心线程数
if (addWorker(command, true)) // 要是成功启动一个新线程作为其第一个任务,就是 true 创建核心线程 并直接 return
return;
c = ctl.get(); // 否则再次获取ctl 的值
}
// 2
// workerCountOf(c) 再次计算线程池的工作线程数 >= 核心线程数 或者 线程池被暂停了
if (isRunning(c) && workQueue.offer(command)) {//上面的if没有return 并且 此时线程池处于运行 且 workQueue.offer(command) 任务已经入队
int recheck = ctl.get(); //再次重新获取 ctl 的值
if (!isRunning(recheck) && remove(command))
// isRunning(recheck) == false 表明 线程不是运行状态了 并且remove(command) 移除成功
reject(command); //执行拒绝策略
else if (workerCountOf(recheck) == 0)
// 要是 工作的线程数 workerCountOf(recheck) == 0,表示此时线程池空闲 ,但是线程池必须要有工作的线程,就要就创建无任务的非核心线程
addWorker(null, false);
}
//3
// workerCountOf(c) 计算线程池的工作线程数 >= 核心线程数 且 workQueue.offer(command) 失败即 阻塞队列满了, 线程池 不处于运行
else if (!addWorker(command, false)) // 就是从 false 创建 非核心线程
reject(command); // 执行拒绝策略
}
//只有这里是 running 才满足 c < SHUTDOWN;
private static boolean isRunning(int c) {
return c < SHUTDOWN;
}
public boolean remove(Runnable task) {
//通过阻塞队列 移除 任务
boolean removed = workQueue.remove(task);
//尝试结束线程池(不一定成功)
tryTerminate(); // In case SHUTDOWN and now empty
//返回移除的结果
return removed;
}
final void reject(Runnable command) {
handler.rejectedExecution(command, this);
}
//当execute无法接受任务时, ThreadPoolExecutor可能调用的方法。
//当没有更多线程或队列槽可用(因为超出了它们的边界)或者执行器关闭时,可能会发生这种情况。
//在没有其他替代方案的情况下,该方法可能会抛出未经检查的RejectedExecutionException ,该异常将传播到execute的调用者。
public interface RejectedExecutionHandler {
void rejectedExecution(Runnable r, ThreadPoolExecutor executor); // 具体实现 见各个拒绝策略的的实现步骤【见下】
}
// CallerRunsPolicy 被拒绝任务的处理程序,直接在execute方法的调用线程中运行被拒绝的任务,除非执行器已关闭,在这种情况下任务将被丢弃。
public static class CallerRunsPolicy implements RejectedExecutionHandler {
public CallerRunsPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 在调用者的线程中执行任务 r,除非执行器已关闭,在这种情况下任务将被丢弃
if (!e.isShutdown()) {
r.run();
}
}
}
// AbortPolicy 抛出RejectedExecutionException的被拒绝任务的处理程序。
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());
}
}
//DiscardPolicy 被拒绝任务的处理程序,会默默地丢弃被拒绝的任务。
public static class DiscardPolicy implements RejectedExecutionHandler {
public DiscardPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
// 不执行任何操作,这会导致丢弃任务 r。
}
}
//DiscardOldestPolicy 被拒绝任务的处理程序,丢弃最旧的未处理请求,然后重试execute ,除非执行器被关闭,在这种情况下任务将被丢弃
public static class DiscardOldestPolicy implements RejectedExecutionHandler {
public DiscardOldestPolicy() { }
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
//获取并忽略 执行器本来要执行的下一个任务(如果该任务立即可用),然后重试执行任务 r,除非执行器关闭,在这种情况下任务 r 将被丢弃。
if (!e.isShutdown()) {
e.getQueue().poll();
e.execute(r);
}
}
}
addWorker()
/*
检查是否可以根据当前池状态和给定边界(核心或最大值)添加新工作线程。
如果是这样,则相应地调整工作线程数,并且如果可能的话,将创建并启动一个新工作线程,并将firstTask作为其第一个任务运行。
如果池已停止或符合关闭条件,此方法将返回 false。
如果线程工厂在询问时未能创建线程,它也会返回 false。
如果线程创建失败,无论是由于线程工厂返回 null,还是由于异常(通常是 Thread.start() 中的 OutOfMemoryError),我们都会干净地回滚。
core:ture表明创建核心线程,false:创建非核心线程
firstTask:不为nuLL,表明是用户提交的任务,为nuLL,表明是线程池调用的
不为 null 先运行提交的任务,再运行阻塞队列的任务
为null ,就直接去阻塞队列拿任务,方式有:
1、超时获取 (超时死亡)
2、阻塞获取(一定获取才结束)
*/
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (;;) { // 死循环
int c = ctl.get(); // 获取 ctl
int rs = runStateOf(c); //获取线程池的运行状态
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && !(rs == SHUTDOWN && firstTask == null &&!workQueue.isEmpty()))
// 非运行状态 !(是停止状态 且 此时没有用户提交的任务只处理阻塞队列的任务 且 任务队列不是空)
return false;
/*
处于此处:
1、线程池处于 运行状态
2、线程池处于 SHUTDOWN 且 非用户提交的任务(firstTask == null) 且 任务队列不是空
*/
for (;;) { // 死循环: 目的 给工作线程数 +1
int wc = workerCountOf(c); // 获取 运行的线程数
if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize))
// 线程数超过 容量 或者 线程数大于核心或者最大线程数
return false; // 返回 false
if (compareAndIncrementWorkerCount(c)) // cas 得 将运行的线程个数 +1
/*
尝试对 ctl 的 workerCount 字段进行 CAS 递增。
private boolean compareAndIncrementWorkerCount(int expect) {
return ctl.compareAndSet(expect, expect + 1);
==> 底层: unsafe.compareAndSwapInt(this, valueOffset, expect, update);如果当前值==预期值,则自动将该值设置为给定的更新值。
}
*/
// cas 的操作成功 结束,退出 for 循环
break retry;
// 一旦 cas 的操作失败
c = ctl.get(); // 重新获取 ctl
if (runStateOf(c) != rs) // 要是运行状态改变了
// 跳过当前循环, 进行下一次循环
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
/*
两个for 循环的作用
到达此处:
1、判断是否可以执行add
2、给线程数工作线程数 +1
*/
// work 是否 启动 成功
boolean workerStarted = false;
// work 是否 添加 成功
boolean workerAdded = false;
Worker w = null;
try {
//创建 worker ,
w = new Worker(firstTask);
// 由 Worker 创建线程
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()); // 获取ctl 线程池的状态
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
// 运行 或者 阻塞但是没有新的任务
/*
运行到此处:
1、线程池为 运行状态
或者
2、状态为 SHUTDOWN,并且是在 阻塞队列里面获取的任务
*/
if (t.isAlive()) // precheck that t is startable
// isAlive 是一个 native 方法 表示测试该线程是否存活。如果线程已启动且尚未死亡,则该线程处于活动状态。
throw new IllegalThreadStateException();
// 线程未死
workers.add(w);// 将创建的 worker 放到 池中所有工作线程的集合中
int s = workers.size(); // 得到集合的大小
if (s > largestPoolSize)
largestPoolSize = s; // 池最大容量进行更新
workerAdded = true; //work 添加 成功
}
} finally {
mainLock.unlock(); // 解锁
}
if (workerAdded) { //线程 添加 成功
t.start(); // 启动线程
//【 此处只知道线程启动任务,但是线程任务执行完之后怎么办===> 此时要去 worker 中查看 】
workerStarted = true; // 线程启动 成功
}
}
} finally {
if (! workerStarted) // 线程启动 失败
addWorkerFailed(w); //进行回滚 操作
}
return workerStarted; // 线程是否 启动 成功
}
addWorkerFailed
/*
回滚工作线程的创建。
将 Worker 从 Workers 移除(如果存在)
减少 Worker 数量
重新检查终止情况,以防该 Worker 的存在阻碍终止
*/
private void addWorkerFailed(Worker w) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (w != null)
workers.remove(w); // worker 不为 null 那么就移除worker
decrementWorkerCount(); // cas 的方式减少 工作的的 个数
// 尝试关闭线程,移除一个线程,可能会使workers为空,所以尝试关闭,但是不一定关闭成功
tryTerminate();
} finally {
mainLock.unlock();
}
}
/**
* 减少 ctl 的workerCount 字段。仅在线程突然终止时才调用此函数
*/
private void decrementWorkerCount() {
do {} while (! compareAndDecrementWorkerCount(ctl.get()));
}
内部类Worker
/**
* Worker 类主要维护运行任务的线程的中断控制状态,以及其他次要的簿记。
此类机会性地扩展 AbstractQueuedSynchronizer 以简化获取和释放围绕每个任务执行的锁。
这可以防止旨在唤醒等待任务的工作线程的中断,而不是中断正在运行的任务。
我们实现一个简单的不可重入互斥锁而不是使用 ReentrantLock,因为我们不希望工作任务在调用像 setCorePoolSize 这样的池控制方法时能够重新获取锁。
此外,为了在线程实际开始运行任务之前抑制中断,我们将锁定状态初始化为负值,并在启动时清除它(在 runWorker 中)。
*/
/*
继承了 AQS 表明这个任务就是一把锁
实现了 Runnable 表明Thread 类可以启动调用这个 work
更加便于管理任务
*/
private final class Worker extends AbstractQueuedSynchronizer implements Runnable {
/**
* This class will never be serialized, but we provide a
* serialVersionUID to suppress a javac warning.
*/
private static final long serialVersionUID = 6138294804551838833L;
/** Thread this worker is running in. Null if factory fails. */
final Thread thread; // 工作的线程
/** Initial task to run. Possibly null. */
Runnable firstTask; // 运行的初始任务
/** Per-thread task counter */
volatile long completedTasks; // 每个线程任务的计数器
/**
* Creates with given first task and thread from ThreadFactory.
* @param firstTask the first task (null if none)
*/
Worker(Runnable firstTask) {
// 设置为 -1 ,表明这个任务 不允许被中断
setState(-1); // inhibit interrupts until runWorker
// 设置任务的执行目标
this.firstTask = firstTask;
// 调用线程工厂创建线程
this.thread = getThreadFactory().newThread(this);【this 就是 Worker】
}
【任务在线程中的执行的入口】
/** Delegates main run loop to outer runWorker */
public void run() {
runWorker(this);
}
// Lock methods
//
// The value 0 represents the unlocked state.
// The value 1 represents the locked state.
protected boolean isHeldExclusively() {
return getState() != 0;
}
protected boolean tryAcquire(int unused) {
if (compareAndSetState(0, 1)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0);
return true;
}
public void lock() { acquire(1); }
public boolean tryLock() { return tryAcquire(1); }
public void unlock() { release(1); }
public boolean isLocked() { return isHeldExclusively(); }
void interruptIfStarted() {
Thread t;
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
}
}
}
}
runWorker
/*
mian worker程序运行循环。重复地从队列中获取任务并执行它们,同时处理一些问题:
1.我们可以从 初始任务 开始,在这种情况下,我们不需要获得第一个任务。否则,只要pool正在运行,我们就会从getTask获取任务。如果它返回null,则由于池状态或配置参数更改,工作线程退出。
其他退出是由异常抛出引起的外部代码,在这种情况下completedsudden保持,这通常导致processWorkerExit替换该线程。
2.在运行任何任务之前,需要获得锁以防止任务执行时其他池中断,然后我们确保除非池停止,否则该线程没有中断集。
3.每个任务运行之前都要调用beforeExecute,这可能会抛出一个异常,在这种情况下,我们导致线程死亡(使用completedsudden为true打破循环),而不处理任务。
4.假设beforeExecute正常完成,我们运行任务,收集其抛出的任何异常发送给afterExecute。我们分别处理RuntimeException, Error(这两个规范都保证我们捕获)和任意Throwables。因为我们不能在Runnable.run中重新抛出Throwables,所以我们在退出时(到线程的UncaughtExceptionHandler)将它们包装在Errors中。任何抛出的异常都会保守地导致线程死亡。
5. 在task.run完成后,调用afterExecute,这也可能抛出异常,这也会导致线程死亡。根据JLS第14.20节,即使task.run抛出,这个异常也会生效。
异常机制的最终效果是,afterExecute和线程的UncaughtExceptionHandler拥有关于用户代码遇到的任何问题的尽可能准确的信息。
*/
final void runWorker(Worker w) {
Thread wt = Thread.currentThread(); // 拿到当前执行的线程
Runnable task = w.firstTask;// 从 worker 中 获取 用户提交的任务
w.firstTask = null; // 对队列中的任务置为null
w.unlock(); // allow interrupts
//解锁:就是将 state 的值 变为 0 ,【对应之前创建 Worker的(worker(...){... setState(-1)...})】 也就是说他是可以 中断 的
// 从构造器创建 到 此处使用 是不允许 中断 的,因为要设置一些准备操作
/*
public void unlock() { release(1); }
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
protected boolean tryRelease(int unused) {
setExclusiveOwnerThread(null);
setState(0); //就是将 state 的值 变为 0
return true;
}
*/
//表示任务是否正常执行完成
boolean completedAbruptly = true; //true 表示任务 未能 正常执行完成
try {
// 循环【重点】
// 一旦 getTask 阻塞 就表明 阻塞队列没有任务,线程池处于空闲状态,线程也是空闲的
while (task != null || (task = getTask()) != null) {
// 有任务 : 来源于 用户提交的任务 或者 调用getTask() 从阻塞队列中拿到任务
w.lock();
// 如果池正在停止,请确保线程被中断;如果没有,请确保线程不被中断。这需要在第二种情况下重新检查以处理 shutdownNow 竞争,同时清除中断
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP)))
&& !wt.isInterrupted())
// 线程状态 > STOP || ( 线程已经被中断 && 线程状态 > stop ) && 获取当前线程状态判断线程是否已经被中断了 false 未被打断
wt.interrupt(); //中断线程
try {
beforeExecute(wt, task); //任务执行前的钩子函数
Throwable thrown = null;
try {
task.run();// 执行任务
/*
Runnable接口应该由其实例旨在由线程执行的任何类来实现。该类必须定义一个名为run的无参数方法。
该接口旨在为希望在活动时执行代码的对象提供通用协议。例如, Runnable是由Thread类实现的。处于活动状态仅仅意味着线程已经启动并且尚未停止。
此外, Runnable提供了使类处于活动状态而不需要子类化Thread方法。
实现Runnable的类可以通过实例化Thread实例并将其自身作为目标传递来运行,而无需子类化Thread 。
在大多数情况下,如果您只计划重写run()方法而不重写其他Thread方法,则应使用Runnable接口。
这很重要,因为除非程序员打算修改或增强类的基本行为,否则不应对类进行子类化。
public interface Runnable {
当使用实现接口Runnable的对象创建线程时,启动线程会导致在该单独执行的线程中调用该对象的run方法。
方法run的一般契约是它可以采取任何操作
public abstract void run();
}
*/
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown); // 任务执行后的执行钩子函数
}
} finally {
task = null; // 任务执行完之后就 置null
w.completedTasks++;// 完成的任务数++
w.unlock();//解锁的目的: 任务执行完,线程处于空闲状态
}
}
completedAbruptly = false; //fasle 表示任务 正常执行完成
} finally {
processWorkerExit(w, completedAbruptly);// 任务的后续处理: worker退出流程
}
}
/*
根据当前的配置设置,对任务执行阻塞或定时等待,或者如果该工作线程由于以下原因必须退出,则返回 null:
1. 工作线程数量超过 maximumPoolSize(由于调用了 setMaximumPoolSize)。
2. 池已停止。
3. 池已关闭且队列为空。
4. 该worker等待任务超时,超时的worker在定时等待前后都会被终止(即allowCoreThreadTimeOut || workerCount > corePoolSize ),并且如果队列非空,则该worker不是池中的最后一个线程
*/
getTask
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out? 上次任务poll()是不是超时了:默认 false 未超时
for (;;) {
// 获取 ctl 值 和 线程池的状态
int c = ctl.get();
int rs = runStateOf(c);
// Check if queue empty only if necessary.
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
// 线程池状态 >= SHUTDOWN && 队列空了,没有任务了 || 线程池状态 >= STOP
decrementWorkerCount();//工作线程数--
return null;
}
/*
1、表明线程池的状态为运行 running
2、线程池状态 >= SHUTDOWN && 阻塞队列还有任务
*/
// 获取 工作线程的数量
int wc = workerCountOf(c);
// Are workers subject to culling?
// allowCoreThreadTimeOut = false(默认) 核心线程即使在空闲时也保持活动(存活、不销毁)态。
// 任务会不会消亡 核心线程即使在空闲时也保持活动(存活、不销毁)态 || 工作线程的数量 > 核心线程的数量
/*
allowCoreThreadTimeOut:true表示核心线程可以被回收,false则表示不回收核心线程(默认)
wc>corePoolS1ze:true表示工作线程数超过核心线程,false表示工作线程数未超过核心线程
timed == true:
表示当前这个线程获取task时 是支持超时机制的,使用queue.poll(XX,XX)
第一个参数是时间,第二个参数是时间单位。当获取task超时的情况下,下一次自旋就可能返回null了。
timed == false:
表示当前这个线程获取task时是不支持超时机制的,当前线程会使用带阻塞的queue.take()方法:
*/
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//第二次之后运行 才会 走这里 此时 工作线程数 > 核心线程数
/*
条件1:(wc > maximumPoolSize|| (timed && timed0ut))
1.1:wc>maximumPoolS1ze何时会成立?
线程池对外提供setMaxinumPoolSize()方法设置最大线程数,所以其他线程会重新设置最大线程数导致该值比初始化的时候大
1.2:(timed&&timed0ut)条件成立:
timed为ture,表明允许回收核心线程或者工作线程大于核心线程 (回收的机制就是使用带超时时间的获取任务方法po11,时间一到,返回 nu11)
timed0ut为ture,表明通过超时获取的任务为null
条件2:(wc>1 workQueue.isEmpty())
2.1:wc>1条件成立,说明当前线程池中还有其他线程,当前线程可以直接回收,返回nu11
2.2:workQueue,isEmpty()前置条件wc==1,条件成立:说明当前任务队列已经空了,最后一个线程,也可以放心的退出。
条件1 && 条件2为 true 表明当前线程达到回收标准
整理一下回收线程的标准:
1、工作线程数大于线程池最大线程数且工作线程数大于1
2、(允许回收核心线程/工作线程大于核心线程)且超时获取任务为nu11,且(工作线程数大于1或队列为空】
*/
if (
// 工作线程的数量 > 最大线程的数量 (会有 setMaximumPoolSize 的方法) || (任务不会被剔除 && 上次poll()超时了)
(wc > maximumPoolSize || (timed && timedOut))
&&
// 工作线程的数量 > 1 || 队列空
(wc > 1 || workQueue.isEmpty())
) {
/*
设置允许的最大线程数。这会覆盖构造函数中设置的任何值。如果新值小于当前值,多余的现有线程将在下次空闲时终止。
public void setMaximumPoolSize(int maximumPoolSize) {
if (maximumPoolSize <= 0 || maximumPoolSize < corePoolSize)
throw new IllegalArgumentException();
this.maximumPoolSize = maximumPoolSize;
if (workerCountOf(ctl.get()) > maximumPoolSize)
interruptIdleWorkers();
}
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
中断可能正在等待任务的线程(如未锁定所示),以便它们可以检查终止或配置更改。
忽略 SecurityExceptions(在这种情况下,某些线程可能保持不间断)。
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
*/
if (compareAndDecrementWorkerCount(c)) // 此时线程会被回收 cas的方式 将工作线程数 -1
return null; //结束 线程消亡
continue; //cas 失败 重新循环
}
//第一次运行 时 只走这里
try {
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
// 任务被剔除 : 超时或者阻塞会抛出异常, 任务未被剔除 : 一直阻塞到 获取任务或者 返回任务
if (r != null)
return r;
// 任务 为 null ,没有获取到任务 表示上次 workQueue.poll() 超时了
timedOut = true;
} catch (InterruptedException retry) {
// 出错也表示 没有超时
timedOut = false;
}
}
}
processWorkerExit
/*
为垂死的 worker 进行清理和簿记。
仅从工作线程调用。除非设置了completedAbruptly,否则假定workerCount 已调整为考虑退出。
此方法从工作集中删除线程,如果由于用户任务异常而退出,或者正在运行的工作线程少于 corePoolSize 或队列非空但没有工作线程,则可能会终止池或替换工作线程。
*/
private void processWorkerExit(Worker w, boolean completedAbruptly) {
if (completedAbruptly) // If abrupt, then workerCount wasn't adjusted
decrementWorkerCount(); // 要是没完成任务 减少线程池中的线程数量
//completedAbruptly = fasle 要是完成了任务
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 将 worker 执行的任务进行累加
completedTaskCount += w.completedTasks;
// 任务队列中删除该任务
workers.remove(w);
} finally {
mainLock.unlock();
}
tryTerminate(); // 线程池退出处理
int c = ctl.get();
if (runStateLessThan(c, STOP)) { //判断线程池状态是不是 ruunning 或者 shutdown
if (!completedAbruptly) { // 要是完成了任务
// 计算当前线程池的工作线程数量
// 计算当前线程池可以预留的最小的线程数
int min = allowCoreThreadTimeOut ? 0 : corePoolSize;
if (min == 0 && !workQueue.isEmpty())
min = 1; //置为1
// 当前线程池中的运行线程的数量 >= 预留的线程的最小数量
if (workerCountOf(c) >= min)
// 此时直接return 线程 消亡
return; // replacement not needed
}
// 线程池中任务执行失败之后,此线程会消亡 并 向线程池中 添加一个线程
// 当前线程池中的运行线程的数量 < 预留的线程池的最小数量 ,需要往线程池中 添加线程
addWorker(null, false);
}
}
线程池结束流程
当不再使用线程池的时候会进行关闭
关闭的方式:
- shutdown():将线程的状态设置为
SHUTDOWN
状态,正在执行的任务会继续执行下去
,没有执行任务 就会中断
- shutdownNow():将 线程 的状态设置为
STOP
状态,正在执行的任务会 被停止
,没有执行任务就 直接返回
shutdown
/**
* 启动有序关闭,其中执行先前提交的任务,但不会接受新任务。如果已经关闭,调用不会产生额外的效果
* 该方法不等待之前提交的任务完成执行。使用awaitTermination来做到这一点
*/
public void shutdown() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
// 检查是不是线程安全的
checkShutdownAccess();
// 将线程池的状态设置为 SHUTDOWN
advanceRunState(SHUTDOWN);
/*
将 runState 转换到给定目标,或者如果至少已经是给定目标,则将其保留。
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
判断线程池的状态是不是 >= targetState 是的话执行break ,否则 可以 cas 处理 拼得 ctl ,然后 break
if (runStateAtLeast(c, targetState) || ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
*/
// 中断处于空闲状态的工作线程。
interruptIdleWorkers();
// 回调钩子函数
onShutdown(); // hook for ScheduledThreadPoolExecutor 钩子方法
} finally {
mainLock.unlock();
}
// 尝试关闭线程池
tryTerminate();
}
interruptIdleWorkers
//中断可能正在等待任务的线程,以便它们可以检查终止或配置更改。忽略 SecurityExceptions(在这种情况下,某些线程可能保持不间断)。
private void interruptIdleWorkers() {
interruptIdleWorkers(false);
}
// onlyOne: true 表示只中断一个未执行的任务,反之 全部任务都中断
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) { // 遍历线程池工作的线程集合,中断所有不忙碌的线程中断
Thread t = w.thread;
// w.tryLock() 尝试加锁成功,表明线程空闲,可以中断,反之线程还在执行任务,无法中断
if (!t.isInterrupted() && w.tryLock()) {
try {
//线程空闲,此处中断
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne) // true 只中断一个就结束循环
break;
}
} finally {
mainLock.unlock();
}
}
shutdownNow
/**
* 尝试停止所有正在执行的任务,停止正在等待的任务的处理,并返回正在等待执行的任务的列表。
* 从此方法返回后,这些任务将从任务队列中排出(删除)。
* 此方法不等待主动执行的任务终止。使用awaitTermination来做到这一点。
* 除了尽最大努力尝试停止处理主动执行的任务之外,没有任何保证。此实现通过Thread.interrupt取消任务,因此任何无法响应中断的任务可能永远不会终止。
*/
public List<Runnable> shutdownNow() {
List<Runnable> tasks; // 定义一个集合,存放没有执行的任务
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
// 为什么加锁: 这里面的操作都是对 原子类 ctl 进行的,ctl 是一个全局变量,所以要加锁操作
try {
checkShutdownAccess();
/*
如果有安全管理器,请确保调用者有权关闭一般线程
如果通过,还确保允许调用者中断每个工作线程。如果 SecurityManager 特别对待某些线程,即使第一次检查通过,情况也可能不成立。
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();
}
}
}
*/
advanceRunState(STOP);
/*
将 runState 转换到给定目标,或者如果至少已经是给定目标,则将其保留。
private void advanceRunState(int targetState) {
for (;;) {
int c = ctl.get();
if (runStateAtLeast(c, targetState) ||
ctl.compareAndSet(c, ctlOf(targetState, workerCountOf(c))))
break;
}
}
*/
// 中断所有的任务
interruptWorkers();
// 获取所有没有执行的任务集合
tasks = drainQueue();
/*
将任务队列排空到新列表中,通常使用drainTo。但是,如果队列是 DelayQueue 或任何其他类型的队列,其中 poll 或 danceTo 可能无法删除某些元素,则会将它们一一删除。
private List<Runnable> drainQueue() {
BlockingQueue<Runnable> q = workQueue;
ArrayList<Runnable> taskList = new ArrayList<Runnable>();
q.drainTo(taskList); 从 q 队列中删除所有可用元素并将它们添加到给定集合 taskList 中
if (!q.isEmpty()) { //调用方法转移一遍之后, q 不为空,转移失败 这个 阻塞队列的类 没有实现这个方法
for (Runnable r : q.toArray(new Runnable[0])) { //手动操作一遍
if (q.remove(r))
taskList.add(r);
}
}
return taskList;
}
*/
} finally {
mainLock.unlock();
}
/*
核心: 尝试终结线程池
*/
tryTerminate();
// 返回没有执行的任务集合
return tasks;
}
public boolean isShutdown() {
return ! isRunning(ctl.get());
}
/**
* 如果此执行器在shutdown或shutdownNow之后正在终止但尚未完全终止,则返回 true。
* 此方法对于调试可能很有用。在关闭后足够长的时间内报告返回true可能表明提交的任务已忽略或抑制中断,导致此执行程序无法正确终止
*/
public boolean isTerminating() {
int c = ctl.get();
return ! isRunning(c) && runStateLessThan(c, TERMINATED);
}
public boolean isTerminated() {
return runStateAtLeast(ctl.get(), TERMINATED);
}
interruptWorkers
中断所有线程,即使处于活动状态。忽略 SecurityExceptions(在这种情况下,某些线程可能保持不间断)。
private void interruptWorkers() {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) 遍历工作线程集合进 中断
w.interruptIfStarted();
} finally {
mainLock.unlock();
}
}
void interruptIfStarted() {
Thread t;
( state=-1 表示任务还处于初始化节点,没有运行,无需中断 )
// 只有 State >= 0 才会中断 线程不是null 线程没有被中断
if (getState() >= 0 && (t = thread) != null && !t.isInterrupted()) {
try {
t.interrupt(); // 线程开始被中断
} catch (SecurityException ignore) {
}
}
}
tryTerminate
/*
如果(关闭且池和队列为空)或(停止且池为空),则转换为 TERMINATED 状态。
如果符合终止条件但workerCount不为零,则中断空闲工作线程以确保关闭信号传播。
必须在任何可能导致终止的操作之后调用此方法 - 减少工作线程数或在关闭期间从队列中删除任务。
该方法是非私有的,允许从 ScheduledThreadPoolExecutor 进行访问
*/
final void tryTerminate() {
for (;;) {
int c = ctl.get();
// 线程池是运行状态 || 运行状态 > TIDYING(已经是 TERMINATED)|| 运行状态= SHUTDOWN 并且 工作队列是非空的 ==> 都直接return 不去尝试暂停线程池
if (isRunning(c) || runStateAtLeast(c, TIDYING) || (runStateOf(c) == SHUTDOWN && !workQueue.isEmpty()))
return;
/*
何时结束线程池
1、线程池的 状态是 STOP
2、线程池 是 SHUTDOWN 且 阻塞队列是空的
*/
if (workerCountOf(c) != 0) { // 判断一下线程池工作线程数量 是不是 0
// 线程池中的 工作线程数量 还是有的,中断一个的线程
interruptIdleWorkers(ONLY_ONE);
return;
}
// 线程池工作线程数量 = 0 才能结束,且只有线程池中的最后一个线程才会走到这里
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
if (ctl.compareAndSet(c, ctlOf(TIDYING, 0))) { //有一个线程 将 ctl 的值变为 TIDYING 中间状态
try {
terminated();
} finally {
ctl.set(ctlOf(TERMINATED, 0)); //finally 中就肯定 也会有一个线程 将 ctl 的值变为 TERMINATED 最终状态
// 唤醒条件队列中的线程,即唤醒所有等待终止的线程
termination.signalAll(); //调用处:
}
return;
}
} finally {
mainLock.unlock();
}
// else retry on failed CAS
}
}
/**
*中断可能正在等待任务的线程(如未锁定所示),以便它们可以检查终止或配置更改。
*/
private void interruptIdleWorkers(boolean onlyOne) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (Worker w : workers) {
Thread t = w.thread;
if (!t.isInterrupted() && w.tryLock()) {
try {
t.interrupt();
} catch (SecurityException ignore) {
} finally {
w.unlock();
}
}
if (onlyOne)
break;
}
} finally {
mainLock.unlock();
}
}
awaitTermination
等待线程池中所有任务完成并终止。
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {
long nanos = unit.toNanos(timeout);
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
for (;;) {
if (runStateAtLeast(ctl.get(), TERMINATED))
return true;
if (nanos <= 0)
return false;
nanos = termination.awaitNanos(nanos); // 阻塞
}
} finally {
mainLock.unlock();
}
}