Java ~ Executor ~ AbstractExecutorService【源码】

前言


 文章

一 AbstractExecutorService(抽象执行器服务)抽象类源码及机制详解


 类

    AbstractExecutorService(抽象执行器服务)抽象类是ExecutorService(执行器服务)接口的抽象实现类,其作用是对执行器服务接口的部分方法定义进行流程规划。所谓流程规划,可以理解为不完整实现。即整体运行流程虽然已经编码,但其中调用的部分方法却没有实现或没有正常实现。这部分方法可能是抽象方法,也可能是直接抛出不支持操作异常的破坏性实现,子类有权利/义务具体实现这些调用方法以使得整个运行流程变得完整可用。这种在父类中规划具体流程而将各个功能的实现细节交由子类负责的编码模式被称为“模板模式”,是常见设计模式中的一种。在Java的各个框架中基本以Abstract为名称开头的类都采用了该模式实现,例如Collection(集)框架的AbstractCollection(抽象集)抽象类、AbstractList(抽象列表)抽象类及AbstractSet(抽象集合)抽象类等。抽象模式的使用极大降低/减少了子类实现的难度/代码量,因为子类无需再去重复的关注/设计/实现那些通用的传递/连接/转换性质的中间代码,而可以集中精力专注在那些具体功能的实现上。不过虽说好处如此,但由于“模板模式”在整体流程的规划上需要兼容所有的子类,因此通常难以保证全局性能的优异性,即无法保证所有子类在各自实现理念上都能达到相对较高的性能。故而即使有时父类已经基于“模板模式”对某方法进行了默认的流程规划,但部分子类出于性能上的考量还是会选择重写该方法。

    抽象执行器服务抽象类规划了执行器服务接口定义的所有与任务递交相关方法的运行流程,该知识点的内容会在下文详述。

/**
 * Provides default implementations of {@link ExecutorService} execution methods. This class implements the {@code submit},
 * {@code invokeAny} and {@code invokeAll} methods using a {@link RunnableFuture} returned by {@code newTaskFor}, which
 * defaults to the {@link FutureTask} class provided in this package. For example, the implementation of
 * {@code submit(Runnable)} creates an associated {@code RunnableFuture} that is executed and returned. Subclasses may
 * override the {@code newTaskFor} methods to return {@code RunnableFuture} implementations other than {@code FutureTask}.
 * 提供执行器服务执行方法的默认实现。该类使用newTaskFor()方法返回的可运行未来实现submit()、invokeAny()及invokeAll()方法,
 * 可运行未来默认为这个包中提供的未来任务类。例如,submit(Runnable)方法实现创建一个相关的可运行未来用于执行和返回。子
 * 类可能重写newTaskFor()方法用于返回不同于未来任务的可运行未来实现(即返回可运行未来接口的其它实现类对象)。
 * <p>
 * <b>Extension example</b>. Here is a sketch of a class that customizes {@link ThreadPoolExecutor} to use a
 * {@code CustomTask} class instead of the default {@code FutureTask}:
 * 衍生案例。这是一个类的草图,关于定制线程池执行器使用定制任务类来替换默认的未来任务类。
 * <pre> {@code
 * public class CustomThreadPoolExecutor extends ThreadPoolExecutor {
 *
 *     static class CustomTask<V> implements RunnableFuture<V> {...}
 *
 *     protected <V> RunnableFuture<V> newTaskFor(Callable<V> c) {
 *         // 返回一个CustomTask类实例。
 *         return new CustomTask<V>(c);
 *     }
 *     protected <V> RunnableFuture<V> newTaskFor(Runnable r, V v) {
 *         // 返回一个CustomTask类实例。
 *         return new CustomTask<V>(r, v);
 *     }
 *     // ... add constructors, etc.
 * }}</pre>
 *
 * @author Doug Lea
 * @Description: 抽象执行器服务
 * @since 1.5
 */
public abstract class AbstractExecutorService implements ExecutorService {
   ...
}

 方法

  • protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) —— 新任务 —— 为指定的可调用/任务创建可运行未来 。
    /**
     * Returns a {@code RunnableFuture} for the given runnable and default value.
     * 为指定可运行和默认值返回一个可运行未来。
     *
     * @param runnable the runnable task being wrapped 被包装的可运行未来
     * @param value    the default value for the returned future 用于返回的未来默认值
     * @param <T>      the type of the given value 指定值的类型
     * @return a {@code RunnableFuture} which, when run, will run the underlying runnable and which, as a {@code Future}, will
     * yield the given value as its result and provide for cancellation of the underlying task
     * 一个可运行未来,当其运行时,将运行底层的可运行。可运行未来作为一个未来,将产生指定的值作为它的结果并提供底层任
     * 务的取消。
     * @Description: 名称:新任务
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:为指定的可运行和用于承接任务执行结果的变量创建一个可运行未来 。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法会使用传入的参数直接创建一个可运行未来。由于任务类型是可运行,因此底层会使用装饰者模式
     * @Description: 封装为了一个可调用。
     * @since 1.6
     */
    protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
        return new FutureTask<T>(runnable, value);
    }
  • protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) —— 新任务 —— 为指定的可调用/任务创建可运行未来 。
    /**
     * Returns a {@code RunnableFuture} for the given callable task.
     * 为指定可调用任务返回一个可运行未来。
     *
     * @param callable the callable task being wrapped 被包装的可调用任务。
     * @param <T>      the type of the callable's result 可调用的结果的类型
     * @return a {@code RunnableFuture} which, when run, will call the underlying callable and which, as a {@code Future}, will
     * yield the callable's result as its result and provide for cancellation of the underlying task RunnableFuture,
     * 一个可运行未来,当其运行时,将调用底层的可调用。可运行未来作为一个未来,将产生可调用的结果作为它的结果并提供底
     * 层任务的取消操作。
     * @Description: 名称:新任务
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:为指定的可调用创建一个可运行未来 。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法会使用传入的参数直接创建一个可运行未来。
     * @since 1.6
     */
    protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
        return new FutureTask<T>(callable);
    }
  • public Future<?> submit(Runnable task) —— 递交 —— 向当前执行器递交可运行任务,并返回追踪/获取可运行任务执行状态/结果的未来。由于在递交可运行任务时没有传入用于承载可运行任务执行结果的变量,因此未来无法获取可运行任务的执行结果,故而该方法返回的未来的get()方法将永远返回null。
        方法会通过newTaskFor(Runnable runnable, T value)方法将指定可运行封装为可运行未来,随后通过调用execute(Runnable command)方法来执行该任务。各种子类通过重写execute(Runnable command)方法来控制任务的执行流程。
    /**
     * @throws RejectedExecutionException {@inheritDoc} 拒绝执行异常
     * @throws NullPointerException       {@inheritDoc} 空指针异常
     * @Description: 名称:递交
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交可运行任务,并返回追踪/获取可运行任务执行状态/结果的未来。由于在递交可运行
     * @Description: 任务时没有传入用于承载可运行任务执行结果的变量,因此未来无法获取可运行任务的执行结果,故而该方法
     * @Description: 返回的未来的get()方法将永远返回null。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法会通过newTaskFor(Runnable runnable, T value)方法将指定可运行封装为可运行未来,随后通过调
     * @Description: 用execute(Runnable command)方法来执行该任务。各种子类通过重写execute(Runnable command)方法来控制任
     * @Description: 务的执行流程。
     */
    @Override
    public Future<?> submit(Runnable task) {
        if (task == null) throw new NullPointerException();
        // 创建一个可运行未来。
        RunnableFuture<Void> ftask = newTaskFor(task, null);
        // execute需在子类重写。
        execute(ftask);
        return ftask;
    }
  • public Future<?> submit(Runnable task) —— 递交 —— 向当前执行器递交可运行任务,并返回追踪/获取可运行任务执行状态/结果的未来。递交可运行任务时会同步传入一个用于承载可运行任务执行结果的变量,该变量承载的可运行任务执行结果即可直接获取【即直接通过result(结果)参数获取】,也会向未来传递,因此该方法返回的未来的get()方法可返回可运行任务执行结果。
        方法会通过newTaskFor(Runnable runnable, T value)方法将指定可运行封装为可运行未来,随后通过调用execute(Runnable command)方法来执行该任务。各种子类通过重写execute(Runnable command)方法来控制任务的执行流程。
    /**
     * @throws RejectedExecutionException {@inheritDoc} 拒绝执行异常
     * @throws NullPointerException       {@inheritDoc} 空指针异常
     * @Description: 名称:递交
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交可运行任务,并返回追踪/获取可运行任务执行状态/结果的未来。递交可运行任务时
     * @Description: 会同步传入一个用于承载可运行任务执行结果的变量,该变量承载的可运行任务执行结果即可直接获取【即直
     * @Description: 接通过result(结果)参数获取】,也会向未来传递,因此该方法返回的未来的get()方法可返回可运行任务执
     * @Description: 行结果。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法会通过newTaskFor(Runnable runnable, T value)方法将指定可运行封装为可运行未来,随后通过调
     * @Description: 用execute(Runnable command)方法来执行该任务。各种子类通过重写execute(Runnable command)方法来控制
     * @Description: 任务的执行流程。
     */
    @Override
    public <T> Future<T> submit(Runnable task, T result) {
        if (task == null) throw new NullPointerException();
        // 返回的可运行未来默认为未来任务。
        RunnableFuture<T> ftask = newTaskFor(task, result);
        execute(ftask);
        return ftask;
    }
  • public Future<?> submit(Runnable task) —— 递交 —— 向当前执行器递交可调用,并返回追踪/获取可调用执行状态/结果的未来。
        方法会通过newTaskFor(Runnable runnable, T value)方法将指定可调用封装为可运行未来,随后通过调用execute(Runnable command)方法来执行该任务。各种子类通过重写execute(Runnable command)方法来控制任务的执行流程。
    /**
     * @throws RejectedExecutionException {@inheritDoc} 拒绝执行异常
     * @throws NullPointerException       {@inheritDoc} 空指针异常
     * @Description: 名称:递交
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交可调用,并返回追踪/获取可调用执行状态/结果的未来。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法会通过newTaskFor(Runnable runnable, T value)方法将指定可调用封装为可运行未来,随后通过调
     * @Description: 用execute(Runnable command)方法来执行该任务。各种子类通过重写execute(Runnable command)方法来控制
     * @Description: 任务的执行流程。
     */
    @Override
    public <T> Future<T> submit(Callable<T> task) {
        if (task == null) throw new NullPointerException();
        RunnableFuture<T> ftask = newTaskFor(task);
        execute(ftask);
        return ftask;
    }
  • private T doInvokeAny(Collection<? extends Callable> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException —— 执行调用任意 —— 向当前执行器递交指定可调用/任务集,并返回其中一个成功执行的可调用/任务的执行结果。该方法会根据参数有限/无限的等待至递交的指定可调用/任务集中的一个执行完成(异常/取消不计算在内)并返回结果;而如果超时则会抛出超时异常。其余的可调用/任务将被取消。由于Java是响应式中断,因此具体表现为等待中的可调用/任务不会再执行,而执行中的可调用/任务如果成功响应则取消;否则(无法/失败响应)任由其继续执行,即不在乎具体的取消结果。而如果所有的可调用/任务都执行失败(异常,取消)则会抛出执行异常。
        方法首先会创建一个未来列表来容纳指定可调用/任务集中所有可调用/任务将会产生的未来。随后循环的依次将可调用/任务递交至完成器(递交返回的未来会被存入未来列表)。在每次递交之前,都会从完成器中尝试获取已结束(完成/异常/取消)可调用/任务的未来,如果获取到了,则递交会暂时中止,随后判断已结束可调用/任务是否是完成。如果是,则直接返回未来中保存的结果以结束循环;否则就说明该已结束可调用/任务为异常或取消,需要继续尝试获取及递交。
        当所有的可调用/任务都被递交至完成器后,根据参数,线程会进行有限/无限的等待,直至获取到完成可调用/任务并通过未来返回结果或因为超时而抛出超时异常为止。除此之外还有一种比较特殊的情况,即递交的所有可调用/任务都已结束(完成/异常/取消),但都不为完成。如此情况下会抛出最后一个可调用/任务的异常(可能是执行异常,也可能是取消/运行时异常),而如果没有记录,则说明是程序没有覆盖到的其它异常,此时会抛出一个默认的执行异常。
        无论最终是否获取到完成的可调用/任务的结果,在方法结束前都要遍历未来列表的中未来以取消所有的可调用/任务。由于已结束(完成/异常/取消)的可调用/任务的未来并不会从未来列表中移除,因此取消是针对所有已递交可调用/任务而言的。对于其中已结束(完成/异常/取消)的可调用/任务取消自然没有意义,取消是针对其中尚未结束(完成/异常/取消)的可调用/任务的。
    /**
     * the main mechanics of invokeAny.
     * invokeAny()方法的主要手段
     *
     * @Description: 名称:执行调用任意
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交指定可调用/任务集,并返回其中一个成功执行的可调用/任务的执行结果。该方法会
     * @Description: 根据参数有限/无限的等待至递交的指定可调用/任务集中的一个执行完成(异常/取消不计算在内)并返回结
     * @Description: 果;而如果超时则会抛出超时异常。其余的可调用/任务将被取消。由于Java是响应式中断,因此具体表现为
     * @Description: 等待中的可调用/任务不会再执行,而执行中的可调用/任务如果成功响应则取消;否则(无法/失败响应)任
     * @Description: 由其继续执行,即不在乎具体的取消结果。而如果所有的可调用/任务都执行失败(异常,取消)则会抛出执
     * @Description: 行异常。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法首先会创建一个未来列表来容纳指定可调用/任务集中所有可调用/任务将会产生的未来。随后循环
     * @Description: 的依次将可调用/任务递交至完成器(递交返回的未来会被存入未来列表)。在每次递交之前,都会从完成器
     * @Description: 中尝试获取已结束(完成/异常/取消)可调用/任务的未来,如果获取到了,则递交会暂时中止,随后判断已
     * @Description: 结束可调用/任务是否是完成。如果是,则直接返回未来中保存的结果以结束循环;否则就说明该已结束可调
     * @Description: 用/任务为异常或取消,需要继续尝试获取及递交。
     * @Description: 当所有的可调用/任务都被递交至完成器后,根据参数,线程会进行有限/无限的等待,直至获取到完成可调用/
     * @Description: 任务并通过未来返回结果或因为超时而抛出超时异常为止。除此之外还有一种比较特殊的情况,即递交的所有
     * @Description: 可调用/任务都已结束(完成/异常/取消),但都不为完成。如此情况下会抛出最后一个可调用/任务的异常(
     * @Description: 可能是执行异常,也可能是取消/运行时异常),而如果没有记录,则说明是程序没有覆盖到的其它异常,此
     * @Description: 时会抛出一个默认的执行异常。
     * @Description: 无论最终是否获取到完成的可调用/任务的结果,在方法结束前都要遍历未来列表的中未来以取消所有的可调
     * @Description: 用/任务。由于已结束(完成/异常/取消)的可调用/任务的未来并不会从未来列表中移除,因此取消是针对所
     * @Description: 有已递交可调用/任务而言的。对于其中已结束(完成/异常/取消)的可调用/任务取消自然没有意义,取消是
     * @Description: 针对其中尚未结束(完成/异常/取消)的可调用/任务的。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 注意:以该方法为底层的方法在调用前需要判断执行器中是否存在尚未结束(完成/异常/取消)可调用/任务,
     * @Description: 如果存在,则方法执行则可能产生混乱,因为方法并不会去判断获取到的已结束(完成/异常/取消)可调用/
     * @Description: 任务是否属于指定可调用/任务集,因此方法可能会返回一个不属于指定可调用/任务集中的可调用/任务结果。
     */
    private <T> T doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos) throws InterruptedException, ExecutionException, TimeoutException {
        // 判断可调用集是否为null,是否为空。
        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)
                        // 如果已递交的可调用/任务总数为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 invokeAny(Collection<? extends Callable> tasks) throws InterruptedException, ExecutionException —— 调用任意 —— 向当前执行器递交指定可调用/任务集,并返回其中一个成功执行的可调用/任务的执行结果。该方法会无限的等待至递交的指定可调用/任务集中的一个执行完成(异常/取消不计算在内)并返回结果。其余的可调用/任务将被取消。由于Java是响应式中断,因此具体表现为等待中的可调用/任务不会再执行,而执行中的可调用/任务如果成功响应则取消;否则(无法/失败响应)任由其继续执行,即不在乎具体的取消结果。而如果所有的可调用/任务都执行失败(异常,取消)则会抛出执行异常。
        该方法直接调用doInvokeAny(Collection<? extends Callable> tasks, boolean timed, long nanos)方法实现。
    /**
     * @Description: 名称:调用任意
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交指定可调用/任务集,并返回其中一个成功执行的可调用/任务的执行结果。该方法会
     * @Description: 无限的等待至递交的指定可调用/任务集中的一个执行完成(异常/取消不计算在内)并返回结果。其余的可调
     * @Description: 用/任务将被取消。由于Java是响应式中断,因此具体表现为等待中的可调用/任务不会再执行,而执行中的可
     * @Description: 调用/任务如果成功响应则取消;否则(无法/失败响应)任由其继续执行,即不在乎具体的取消结果。而如果
     * @Description: 所有的可调用/任务都执行失败(异常,取消)则会抛出执行异常。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:该方法直接调用doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos)方法
     * @Description: 实现。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 注意:以该方法为底层的方法在调用前需要判断执行器中是否存在尚未结束(完成/异常/取消)可调用/任务,
     * @Description: 如果存在,则方法执行则可能产生混乱,因为方法并不会去判断获取到的已结束(完成/异常/取消)可调用/
     * @Description: 任务是否属于指定可调用/任务集,因此方法可能会返回一个不属于指定可调用/任务集中的可调用/任务结果。
     */
    @Override
    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 invokeAny(Collection<? extends Callable> tasks, long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException —— 调用任意 —— 向当前执行器递交指定可调用/任务集,并返回其中一个成功执行的可调用/任务的执行结果。该方法会根据参数有限的等待至递交的指定可调用/任务集中的一个执行完成(异常/取消不计算在内)并返回结果;而如果超时则会抛出超时异常。其余的可调用/任务将被取消。由于Java是响应式中断,因此具体表现为等待中的可调用/任务不会再执行,而执行中的可调用/任务如果成功响应则取消;否则(无法/失败响应)任由其继续执行,即不在乎具体的取消结果。而如果所有的可调用/任务都执行失败(异常,取消)则会抛出执行异常。
        该方法直接调用doInvokeAny(Collection<? extends Callable> tasks, boolean timed, long nanos)方法实现。
    /**
     * @Description: 名称:调用任意
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交指定可调用/任务集,并返回其中一个成功执行的可调用/任务的执行结果。该方法会
     * @Description: 根据参数有限的等待至递交的指定可调用/任务集中的一个执行完成(异常/取消不计算在内)并返回结果;而
     * @Description: 如果超时则会抛出超时异常。其余的可调用/任务将被取消。由于Java是响应式中断,因此具体表现为等待中
     * @Description: 的可调用/任务不会再执行,而执行中的可调用/任务如果成功响应则取消;否则(无法/失败响应)任由其继
     * @Description: 续执行,即不在乎具体的取消结果。而如果所有的可调用/任务都执行失败(异常,取消)则会抛出执行异常。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:该方法直接调用doInvokeAny(Collection<? extends Callable<T>> tasks, boolean timed, long nanos)方法
     * @Description: 实现。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 注意:以该方法为底层的方法在调用前需要判断执行器中是否存在尚未结束(完成/异常/取消)可调用/任务,
     * @Description: 如果存在,则方法执行则可能产生混乱,因为方法并不会去判断获取到的已结束(完成/异常/取消)可调用/
     * @Description: 任务是否属于指定可调用/任务集,因此方法可能会返回一个不属于指定可调用/任务集中的可调用/任务结果。
     */
    @Override
    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 List<Future> invokeAll(Collection<? extends Callable> tasks) throws InterruptedException —— 调用所有 —— 向当前执行器递交可调用/任务集,并返回追踪/获取可调用/任务执行状态/结果的未来集。该方法会等待至指定的可调用/任务集中的可调用/任务全部结束(完成/异常/取消)才会返回,因此返回的未来集中每个未来的isDone()方法结果都为true。
        方法会遍历指定可调用/任务集,将所有的可调用/任务都递交并将生成的未来加入未来列表中。随后遍历未来列表,通过get()方法等待每个可调用/任务完成,并将未来列表返回。
    /**
     * @Description: 名称:调用所有
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交可调用/任务集,并返回追踪/获取可调用/任务执行状态/结果的未来集。该方法会等
     * @Description: 待至指定的可调用/任务集中的可调用/任务全部结束(完成/异常/取消)才会返回,因此返回的未来集中每个
     * @Description: 未来的isDone()方法结果都为true。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法会遍历指定可调用/任务集,将所有的可调用/任务都递交并将生成的未来加入未来列表中。随后遍
     * @Description: 历未来列表,通过get()方法等待每个可调用/任务完成,并将未来列表返回。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 注意:如果某个可调用/任务在执行execute(Runnable command)方法过程中异常,则后续的可调用/任务不会再
     * @Description: 递交,且之前递交的可调用/任务也会被取消。因此,在方法抛出异常的情况下,未来列表中并不一定包含所有
     * @Description: 可调用/任务的未来。
     */
    @Override
    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) {
                // 这里不可以直接调用submit(Callable<T> task),因为由于execute(f)方法的实现未知,因此execute(f)方法可能会抛出
                // 异常,这种情况下如果把"将未来加入未来列表"放在execute(Runnable command)方法之后则可能会导致未来列表中丢
                // 失一个代理可调用/任务已"递交"的未来...递交丢失和未递交丢失是两个概念...我猜的...
                RunnableFuture<T> f = newTaskFor(t);
                futures.add(f);
                execute(f);
            }
            // 遍历未来列表,判断每个未来的代理可调用/任务是否结束(完成/异常/取消),如果没有,则调用get()方法等待其结
            // 束(完成/异常/取消)。
            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 List<Future> invokeAll(Collection<? extends Callable> tasks, long timeout, TimeUnit unit) throws InterruptedException —— 调用所有 —— 向当前执行器递交可调用/任务集,并返回追踪/获取可调用/任务执行状态/结果的未来集。该方法会在指定等待时间内等待指定的可调用/任务集中的调用/任务结束(完成/异常/取消),如果超时则会取消其中未结束(等待中/执行中)的可调用/任务,因此返回的未来集中每个未来的isDone()方法结果都为true。由于Java是响应式中断,因此具体表现为等待中的可调用/任务不会再执行,而执行中的可调用/任务如果成功响应则取消;否则(无法/失败响应)任由其继续执行,即不在乎具体的取消结果。
        方法会遍历指定可调用/任务集,将所有的可调用/任务都递交并将生成的未来加入未来列表中。随后两次遍历未来列表:一次执行所有的可调用/任务;一次通过get()方法等待每个可调用/任务完成。之所以将可调用/任务的封装和执行用两次循环完成,是因为execute(Runnable command)方法也会消耗超时时间,因此在有限的时间内可能无法将所有的可调用/任务都封装为未来并加入未来列表中。这是不允许的,因为理论上只有execute(Runnable command)方法发生异常的时候才会出现这样的情况。
        当超时时间到达后,如果还有可调用/任务未结束,则还需要取消这些可调用/任务。
    /**
     * @Description: 名称:调用所有
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 作用:向当前执行器递交可调用/任务集,并返回追踪/获取可调用/任务执行状态/结果的未来集。该方法会在
     * @Description: 指定等待时间内等待指定的可调用/任务集中的调用/任务结束(完成/异常/取消),如果超时则会取消其中未
     * @Description: 结束(等待中/执行中)的可调用/任务,因此返回的未来集中每个未来的isDone()方法结果都为true。由于Java
     * @Description: 是响应式中断,因此具体表现为等待中的可调用/任务不会再执行,而执行中的可调用/任务如果成功响应则取
     * @Description: 消;否则(无法/失败响应)任由其继续执行,即不在乎具体的取消结果。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 逻辑:方法会遍历指定可调用/任务集,将所有的可调用/任务都递交并将生成的未来加入未来列表中。随后两
     * @Description: 次遍历未来列表:一次执行所有的可调用/任务;一次通过get()方法等待每个可调用/任务完成。之所以将可调
     * @Description: 用/任务的封装和执行用两次循环完成,是因为execute(Runnable command)方法也会消耗超时时间,因此在有
     * @Description: 限的时间内可能无法将所有的可调用/任务都封装为未来并加入未来列表中。这是不允许的,因为理论上只有
     * @Description: execute(Runnable command)方法发生异常的时候才会出现这样的情况。
     * @Description: 当超时时间到达后,如果还有可调用/任务未结束,则还需要取消这些可调用/任务。
     * @Description: --------------------------------------------------------------------------------------------------------------------------------------
     * @Description: 注意:~
     */
    @Override
    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);
        }
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

说淑人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值