_2Executor框架, 分析过程中的Demo
Executor框架的主要类有:
- 任务接口:有2种,没有返回值的Runnable,有返回值的Callable
- 任务结果接口:Future 代表一个任务的执行结果,由于Thread里面只支持Runnable类型,所以在实现的时候,Callable的实现类RunnableAdapter里面封装了一个Runnable对象,result对应Future
- 任务执行:Executor代表了定义了任务执行动作
- 任务执行服务:扩展了Executor,添加了submit方法,支持传入Runnable和Callable任务
- 抽象任务执行类:提供了newTaskFor来创建任务,支持Runnable和Callable任务2种,传入Callable的时候,被封装成FutureTask;submit也支持Runnable和Callable任务2种,都转换成RunnableFuture
1.Task相关接口定义
任务接口有2种,原生包里面有Runnable,并发包里面扩展了一个Callable,和Runnable不同的地方是,Callable有返回值
public interface Callable<V> {
V call() throws Exception;
}
public interface Runnable {
public abstract void run();
}
Future接口定义了一个异步任务的执行结果,提供了方法来检查任务的执行情况,如是否完成、取消和获取结果等
public interface Future<V> {
boolean cancel(boolean mayInterruptIfRunning);
boolean isCancelled();
boolean isDone();
V get() throws InterruptedException, ExecutionException;
V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException;
}
一般使用FutureTask来作为异步任务,实现了RunnableFuture接口,RunnableFuture接口同时继承了Runnable和Future接口
public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
//
public class FutureTask<V> implements RunnableFuture<V>
重点看一下FutureTask里面的实现,关键属性说明
- volatile int state 任务的执行状态
- Callable callable 任务里面的callable,在run方法里面调用callable.gcall方法
- Object outcome 代表callable.gcall方法的结果,使用get方法来获取
- volatile Thread runner 任务执行所在的线程
- volatile WaitNode waiters 任务队列
任务可能的状态有
NEW -> COMPLETING -> NORMAL
NEW -> COMPLETING -> EXCEPTIONAL
NEW -> CANCELLED
NEW -> INTERRUPTING -> INTERRUPTED
关键方法有
- FutureTask 构造对象
- run 执行任务
- get 获取任务执行结果
- cancel 取消任务
- isDone 任务是否完成
FutureTask类里面提供了2个构造方法
public FutureTask(Callable<V> callable)
public FutureTask(Runnable runnable, V result)
针对传入Runnable的方法,会调用Executors.callable进行转换,转换成一个Callable对象返回,实际返回的是一个RunnableAdapter对象,
public static <T> Callable<T> callable(Runnable task, T result) {
if (task == null)
throw new NullPointerException();
return new RunnableAdapter<T>(task, result);
}
此对象继承自Callable,在call方法里面,会调用runnable对象的run方法,然后返回执行结果 result
RunnableAdapter<T> implements Callable<T> {
private final Runnable task;
private final T result;
RunnableAdapter(Runnable task, T result) {
this.task = task;
this.result = result;
}
public T call() {
// 用runnable构造callable对象的时候,runnable.run方法是在这个地方调用
task.run();
return result;
}
}
然后再看一下此类的一个核心方法run,此方法里面的2个主要功能是执行Callable.call方法,然后设置执行结果,提供给get方法返回
public void run() {
// 使用CAS来设置runner线程对象
if (state != NEW ||
!RUNNER.compareAndSet(this, null, Thread.currentThread()))
return;
try {
Callable<V> c = callable;
if (c != null && state == NEW) {
V result;
boolean ran;
try {
// 调用Callable.call方法,关键代码逻辑在此方法里面实现
result = c.call();
ran = true;
} catch (Throwable ex) {
}
if (ran)
// 设置执行结果和state状态为完成
set(result);
}
} finally {
}
}
再看下get方法的实现
public V get(long timeout, TimeUnit unit)
throws InterruptedException, ExecutionException, TimeoutException {
if (unit == null)
throw new NullPointerException();
int s = state;
if (s <= COMPLETING &&
(s = awaitDone(true, unit.toNanos(timeout))) <= COMPLETING)
throw new TimeoutException();
return report(s);
}
如果任务还没有完成,则调用awaitDone方法,等待任务完成、取消或被中断,在一个死循环里面执行如下逻辑
- 如果大于COMPLETING状态,则返回当前state
- 如果是COMPLETING状态,则调用Thread.yield()方法让出CPU调度
- 如果任务节点没有创建,则创建一个任务节点
- 没有任务节点没有加入队列,则使用CAS来加入队列
- 如果线程被中断,则删除任务节点并抛出异常
- 如果支持超时,则根据时间来调用LockSupport.park进入等待,超时则直接返回
- 非以上几种情况,直接LockSupport.park进入等待,等待被唤醒
2.任务调度
Executor接口定义了任务执行,ExecutorService接口扩展了Executor接口,新增加了任务提交、中止、关闭和获取结果接口,用来管理一个或多个异步任务的执行
public interface Executor {
void execute(Runnable command);
}
public interface ExecutorService extends Executor {
void shutdown();
List<Runnable> shutdownNow();
boolean isShutdown();
boolean isTerminated();
boolean awaitTermination
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
<T> List<Future<T>> invokeAll
<T> T invokeAny
}
抽象类AbstractExecutorService实现了ExecutorService接口,提供了2个工厂方法newTaskFor来创建任务,返回FutureTask对象。
submit方法有3个重载的方法,传入的参数不一样,最终都转换成Callable对象,并调用executre方法来执行任务
public <T> Future<T> submit(Callable<T> task) {
if (task == null) throw new NullPointerException();
RunnableFuture<T> ftask = newTaskFor(task);
execute(ftask);
return ftask;
}
2.1 ThreadPoolExecutor类
重点看ThreadPoolExecutor类,继承了AbstractExecutorService,关键属性
- final AtomicInteger ctl 线程状态(高3位)和工作线程数量(剩下的29位,最大容量是2^29-1)
- final BlockingQueue workQueue 任务队列,有3种:无界队列、有界队列和同步移交SynchronousQueue。其中有界队列包括ArrayBlockingQueue、有界的LinkedBlockingQueue和PriorityBlockingQueue;只有当线程池是无界的或任务可以拒绝时,SynchronousQueue才有实际意义
- HashSet workers 保存线程池
- RejectedExecutionHandler handler 任务拒绝策略
- volatile long keepAliveTime 存活时间,如果某个线程的空闲时间超过了存活时间,那么会被标记可回收,并且当线程线程池的大小超过基本大小的时候,这个线程将被终止
- volatile boolean allowCoreThreadTimeOut 是否允许基本线程被回收,默认是false,如果为true,则使用keepAliveTime来确认等待任务是否超时
- volatile int corePoolSize 线程池的基础大小,没有任何任务执行时线程池的大小,并且只有在工作队列满的情况下会创建超过这个数量的线程
- volatile int maximumPoolSize 线程池最大线程数量
只有当任务都是相同类型且互相独立时,线程池的性能才能最大化。在线程池中,如果任务依赖于其它任务,则可能产出死锁
对于计算密集型,在有N个CPU的处理器上,线程池大小设置为N+1最优;对于包括IO或其它阻塞任务时,N=NCPU * UCPU * (1+w/c)
其中UCPU代表CPU利用率,0 <= UCPU <= 1
w/c 等待时间/计算时间
关于ctl相关的设计以及值的获取
- COUNT_MASK = 2^29-1,低28位全为1
- 线程运行状态获取runState,取高3位的值,低29位取反,& 操作后低29位直接为0
- 获取运行线程的数量workerCount,直接&,取低29位的值,高3位为0,&后还是为0
- 获取ctl的值 rs | wc ,取runState和workerCount的并值,runState的高3位和workerCount的低29位
private static int runStateOf(int c) { return c & ~COUNT_MASK; }
private static int workerCountOf(int c) { return c & COUNT_MASK; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
任务执行的大概流程如下:
execute --> addWorkers --> new Worker --> worker.start --> worker.run --> runWorker 循环调用getTask获取下一条要执行的任务
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
int c = ctl.get();
// 如果线程池中的线程数量少于corePoolSize,则尝试启动一个新的线程,并把command作为第一个任务来执行
if (workerCountOf(c) < corePoolSize) {
// 在addWorker的时候,会自动检查运行状态和任务数量
if (addWorker(command, true))
return;
c = ctl.get();
}
// 如果一个任务可以成功加入队列,还需要再次检查是否需要再启动一个线程
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
// 如果不能加入队列,则尝试启动一个新的线程,如果失败则reject任务
else if (!addWorker(command, false))
reject(command);
}
在addWorker方法里面
// 检查是否需要创建一个新的Worker添加到线程池里面
private boolean addWorker(Runnable firstTask, boolean core) {
retry:
for (int c = ctl.get();;) {
// 如果任务已经结束或任务队列为空,则直接返回false,不需要再创建
if (runStateAtLeast(c, SHUTDOWN)
&& (runStateAtLeast(c, STOP)
|| firstTask != null
|| workQueue.isEmpty()))
return false;
for (;;) {
// 如果线程池的数量大于或等于最大容量,则返回false,不能创建
if (workerCountOf(c)
>= ((core ? corePoolSize : maximumPoolSize) & COUNT_MASK))
return false;
// 增加一个Worker并跳出循环
if (compareAndIncrementWorkerCount(c))
break retry;
c = ctl.get(); // Re-read ctl
// 如果状态为SHUTDOWN,则重试
if (runStateAtLeast(c, SHUTDOWN))
continue retry;
// else CAS failed due to workerCount change; retry inner loop
}
}
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
// 创建一个新的Worker,在DefaultThreadFactory里面创建一个新的线程,会传入的是一个Runnable firstTask
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 c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && 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) {
// 执行firstTask,最终调用runWorker
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
runWorker方法循环从任务队列里面获取任务并执行
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
// 循环调用getTask()从workQueue里面获取任务
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
try {
// 执行任务
task.run();
afterExecute(task, null);
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
总结一下执行流程如下:
- 如果线程池中的线程数量少于corePoolSize,则addWorker尝试启动一个新的线程,并把command作为第一个任务来执行。
- 线程池中的线程数量大于corePoolSize
- 如果一个任务可以成功加入队列,还需要再次检查是否需要addWorker再启动一个线程
- 如果不能加入队列,则尝试addWorker启动一个新的线程,如果失败则reject任务
在addWorker方法里面
- 如果任务已经结束或任务队列为空,则直接返回false,不需要再创建
- 如果线程池的数量大于或等于最大容量,则返回false,不能创建
- 如果能成功增加运行线程的数量,则跳出循环,如果失败则重试
- 创建一个新的Worker并加入线程池,执行firstTask,最终调用runWorker
- 在runWorker 方法里面,循环调用getTask()从workQueue里面获取任务并执行
2.2 Executors类
工厂类,提供方法
- newFixedThreadPool 固定线程数量的ThreadPoolExecutor,corePoolSize和maximumPoolSize都是传入的参数,有界队列LinkedBlockingQueue
- newSingleThreadExecutor 参数corePoolSize和maximumPoolSize都是1的ThreadPoolExecutor,有界队列LinkedBlockingQueue
- newCachedThreadPool corePoolSize是0和maximumPoolSize是Integer.MAX_VALUE,keepAliveTime是60s,有界队列SynchronousQueue
- newSingleThreadScheduledExecutor corePoolSize是1,maximumPoolSize是Integer.MAX_VALUE的ScheduledThreadPoolExecutor(继承自ThreadPoolExecutor)
- newScheduledThreadPool corePoolSize是传入参数的ScheduledThreadPoolExecutor
- unconfigurableExecutorService 没有配置ExecutorService,使用传入的参数ExecutorService
- newWorkStealingPool 返回ForkJoinPool(继承自AbstractExecutorService)
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ExecutorService unconfigurableExecutorService(ExecutorService executor) {
if (executor == null)
throw new NullPointerException();
return new DelegatedExecutorService(executor);
}