_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);
        }
    }

总结一下执行流程如下:

  1. 如果线程池中的线程数量少于corePoolSize,则addWorker尝试启动一个新的线程,并把command作为第一个任务来执行。
  2. 线程池中的线程数量大于corePoolSize
  • 如果一个任务可以成功加入队列,还需要再次检查是否需要addWorker再启动一个线程
  • 如果不能加入队列,则尝试addWorker启动一个新的线程,如果失败则reject任务

在addWorker方法里面

  1. 如果任务已经结束或任务队列为空,则直接返回false,不需要再创建
  2. 如果线程池的数量大于或等于最大容量,则返回false,不能创建
  3. 如果能成功增加运行线程的数量,则跳出循环,如果失败则重试
  4. 创建一个新的Worker并加入线程池,执行firstTask,最终调用runWorker
  5. 在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);
    }