【Java编程的逻辑】异步任务执行服务 Executor和ExecutorService

基本概念

线程Thread即表示要执行的任务,又表示执行的机制。
Java并发包提供了一套“异步任务执行服务”机制,将“任务的提交”和“任务的执行”相分离。

任务执行服务涉及到的基本接口:

  • Runnable和Callable:表示要执行的异步任务
  • Executor和ExecutorService:表示执行服务
  • Future:表示异步任务的结果

Runnable和Callable都是接口,Runnable没有返回结果,而Callable有,Runnable不会抛出异常,而Callable会。

Executor表示最简单的执行服务

public interface Executor {
    void execute(Runnable command);
}

可以执行一个Runnable,没有返回结果。接口没有限定任务如何执行,可能是创建一个新线程,可能是复用线程池中的某个线程

ExecutorService扩展了Executor,定了更多服务
先来看submit方法,submit表示提交一个任务,返回值类型都是Future,返回后,只是表示任务已提交,不代表已执行,通过Future可以查询异步任务的状态、获取最终结果、取消任务等。

public interface ExecutorService extends Executor { 
    // 对于Callable,任务最终有个返回值
    <T> Future<T> submit(Callable<T> task);
    // Runnable是没有返回值的,但可以提供一个结果,在异步任务结束时返回
    <T> Future<T> submit(Runnable task, T result);
    // 最终返回null
    Future<?> submit(Runnable task);
} 

再来看看Future的定义:

public interface Future<V> { 
    // 用于取消异步任务,如果任务已完成、或已取消、或由于某种原因不能取消,返回false,否则返回true
    // 如果任务还未开始,则不再运行。如果任务已经在运行,则不一定能取消   
    // 参数mayInterruptIfRunning表示,如果任务正在执行,是否调用interrupt方法中断线程,如果为false就不会,如果为true就会尝试中断线程,中断不一定能取消线程  
    boolean cancel(boolean mayInterruptIfRunning);   
    // 表示任务是否被取消,只要cancel方法返回了true,随后的isCancelled方法都会返回true,即使执行任务的线程还未真正结束  
    boolean isCancelled(); 
    // 表示任务是否结算,不管什么原因导致结束的
    boolean isDone(); 
    // 返回执行结果,如果任务是Runnable且没有提供结果,返回null
    // 任务被取消了,会抛出CancellationException 
    V get() throws InterruptedException, ExecutionException; 
    V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException;
}

基本使用

public class Test {
    static class Task implements Callable<Integer> {
        @Override
        public Integer call() throws Exception {
            int sleepSeconds = new Random().nextInt(1000);
            Thread.sleep(sleepSeconds);
            return sleepSeconds;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // 创建一个任务执行服务
        ExecutorService executor = Executors.newSingleThreadExecutor();
        Future<Integer> future = executor.submit(new Task());
        Thread.sleep(100);
        try {
            System.out.println(future.get());
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
        // 关闭任务执行服务
        executor.shutdown();
    }
}

ExecutorService还有如下几个方法:

public interface ExecutorService extends Executor { 
    // 不再接受新任务,但已提交的任务会继续执行,即使任务还未执行
    void shutdown();
    // 不接口新任务,且会终止已提交但未执行的任务,对于正在执行的任务,一般会调用线程的interrupt方法尝试中断
    // 返回已提交但尚未执行的任务列表  
    List<Runnable> shutdownNow();   

    // showdown和showdownNow不会阻塞,它们返回后不代表所有任务都已结束,但isShutdown会返回ture
    boolean isShutdown();

    // 除非首先调用shutdown或shutdownNow,否则isTerminated永不为true。
    // 当调用shutdown()方法后,并且所有提交的任务完成后返回为true;
    // 当调用shutdownNow()方法后,成功停止后返回为true;
    boolean isTerminated(); 

    // 等待所有任务结束,可以限定等待的时间 
    // 如果超时前所有任务都结束了,则返回true,否则返回false
    boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException;

    // 等待所有任务完成,返回Future列表 
    // 每个Future的isDone都返回true,不过isDone不代表任务执行成功了,可能是被取消了 
    <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) 
                    throws InterruptedException; 
    <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;     
}

实现原理

ExecutorService的主要实现类是ThreadPoolExecutor,它是基于线程实现的,继承于AbstractExecutorService。AbstractExecutorService是一个抽象类,实现了ExecutorService的部分方法。

AbstractExecutorService

AbstractExecutorService提供了submit、invokeAll、invokeAny的默认实现,子类需要实现其他方法。
除了execute,其他方法都与执行服务的生命周期管理有关,submit/invokeAll/invokeAny最终都会调用execute,execute决定了到底如何执行任务。

我们可以先看看submit方法

public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);
    return ftask;
}

调用newTaskFor生成了一个RunnableFuture,RunnableFuture是一个接口,既扩展了Runnable,又扩展了Future,没有定义新的方法。作为Runnable它表示要执行的任务,传递给execute进行执行;作为Future它表示任务执行的异步结果。

我们再看看newTaskFor

protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}

FutureTask实现了RunnableFuture接口

FutureTask

public class FutureTask<V> implements RunnableFuture<V> {
    // 表示状态  
    private volatile int state;
    // 刚开始的状态或任务在运行
    private static final int NEW          = 0;
    // 临时状态,任务即将结果,在设置结果
    private static final int COMPLETING   = 1;
    // 任务正常执行完成
    private static final int NORMAL       = 2;
    // 任务执行抛出异常结束
    private static final int EXCEPTIONAL  = 3;
    // 任务被取消
    private static final int CANCELLED    = 4;
    // 任务在被中断
    private static final int INTERRUPTING = 5;
    // 任务被中断
    private static final int INTERRUPTED  = 6;

    // 表示待执行的任务
    private Callable<V> callable;

    // 表示最终的执行结果或异常
    private Object outcome;

    // 表示运行任务的线程
    private volatile Thread runner;

    // 单向链表,表示等待任务执行结果的线程
    private volatile WaitNode waiters;

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        // 初始化状态
        this.state = NEW;       // ensure visibility of callable
    }

    public FutureTask(Runnable runnable, V result) {
        // 如果传入的是runnable,则转换为callable
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
}

任务执行服务会使用一个线程执行FutureTask的run方法

public void run() {
    if (state!= NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     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) {
                // 捕捉异常,异常保存到outcome并调用finishCompletion唤醒所有等待结果的线程
                result = null;
                ran = false;
                setException(ex);
            }
            // 设置结果,保存到outcome并调用finishCompletion唤醒所有等待结果的线程
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

任务提交者,通过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();
    // 调用report报告结果,report根据状态返回结果或抛出异常
    return report(s);
}

private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

猜你喜欢

转载自blog.csdn.net/u013435893/article/details/80182983