假装很懂CompletableFuture

正题

CompletableFuture是JDK1.8才出现的,至于是否拥有很强大的功能其实我也未在工作上实践过,不过话说回来,即使实践过当时的我也是看不懂地,因为我现在才有时间来对它做一个了解,在此之前先来看看它的父接口-CompletionStage与Future。对于CompletionStage来说,它被认为是一个执行的阶段,可以是同步或异步,每一个阶段完成的同时有可能触发其他阶段,也就是说阶段之间是可以相互依赖的,好比是流水作业,虽然它可以执行各种计算,即使是复杂的链式计算也是手到擒来,但也存在一些弊端,比如无法探测计算是否完成或获取计算的结果或等待其阶段执行完成,所以为了使其更健壮,它又实现了Future接口,可它又与Future的实现类有着区别,比如对于cancel来说,它会当作是异常执行完成。CompletableFuture是两者的结合物,提供的方法有很多种,简单总结下。

带有后缀名为Async的方法表示以异步的方式执行任务,通常情况下使用ForkJoinPool公共线程池;带有前缀名为then的方法表示阶段之间具有依赖关系,需要上一个阶段执行完毕后才能触发下一个阶段;带有后缀名为Either的方法表示在多重依赖下只会依赖其中任何一个阶段,即任何一个阶段执行完成即可执行当前阶段;

在阅读源码之前,读者最好能把CompletableFuture、Completion、UniCompletion等之间的数据结构画出来,清晰的结构关系能够帮助理解,在下面的代码中会提到一些个人对相关类的理解与称谓。

数据结构

为了方便理解,将每个类都加上一个称谓,同时说明之间的关系:

  • CompletableFuture:阶段,一个阶段自身只有一个步骤,一个阶段可以依赖另一个阶段,在这种情况下通常会将依赖阶段的步骤放入到被依赖阶段的链表中,等到被依赖阶段执行完成后会通知执行链表,以此来执行依赖阶段

  • Completion:步骤,当前步骤可以关联下一个步骤

  • UniApply:步骤,因为其是Completion的子类


    public class CompletableFuture<T> implements Future<T>, CompletionStage<T> {

        /**
         * 执行完成的结果
         * 若是正常执行且有设置结果的话则直接返回结果,若无设置结果则返回null 
         * 若是异常完成则会抛出异常,通过AltResult对象来包装异常信息
         */
        volatile Object result;

        /**
         * 依赖于当前阶段的阶段的步骤
         * 只有在当前阶段执行完成后才会通知执行依赖阶段的步骤,否则就不具有依赖关系了,而通知的具体方法就是postComplete
         */
        volatile Completion stack;

        // 表示当前阶段是同步直接执行
        static final int SYNC   =  0;

        // 表示当前阶段是异步直接执行
        static final int ASYNC  =  1;

        // 表示当前阶段是由嵌套引发执行,即postComplete引发执行
        static final int NESTED = -1;

        /**
         * 若公共线程池的并行数大于1,即工作线程数大于1,则使用公共线程池
         */
        private static final boolean useCommonPool = (ForkJoinPool.getCommonPoolParallelism() > 1);

        /**
         * 通常情况下使用公共线程池
         */
        private static final Executor asyncPool = useCommonPool ? ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

        /**
         * 包装执行结果为null
         */
        static final AltResult NIL = new AltResult(null);
    }

构造函数


    /**
     * 初始化
     */
    public CompletableFuture() {

    }

    /**
     * 初始化
     * @param r 执行结果
     */
    private CompletableFuture(Object r) {
        this.result = r;
    }

简单方法


    /**
     * 异步执行任务并设置执行结果值,默认情况下的执行器是ForkJoinPool,即公共线程池
     * 每次调用该方法都会生成新的CompletableFuture对象
     * @param supplier 带有执行结果的任务
     * @return CompletableFuture新实例
     */
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    }

    /**
     * 使用指定执行器异步执行任务并设置执行结果值
     * @param supplier 带有执行结果的任务
     * @param executor 指定执行器
     * @return CompletableFuture新实例
     */
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }

    /**
     * 校验执行器
     * @param e 执行器
     * @return 执行器
     */
    static Executor screenExecutor(Executor e) {
        if (!useCommonPool && e == ForkJoinPool.commonPool())
            return asyncPool;
        if (e == null) throw new NullPointerException();
        return e;
    }

    /**
     * 使用指定执行器异步执行任务
     * @param e 指定执行器
     * @param f 带有执行结果的任务
     * @return CompletableFuture新实例
     */
    static <U> CompletableFuture<U> asyncSupplyStage(Executor e, Supplier<U> f) {
        if (f == null) throw new NullPointerException();
        CompletableFuture<U> d = new CompletableFuture<U>();
        e.execute(new AsyncSupply<U>(d, f));
        return d;
    }

    @SuppressWarnings("serial")
    static final class AsyncSupply<T> extends ForkJoinTask<Void> implements Runnable, AsynchronousCompletionTask {

        // 当前阶段
        CompletableFuture<T> dep;

        // 当前阶段的执行结果
        Supplier<T> fn;

        /**
         * 初始化
         * @param dep 当前阶段
         * @param fn 当前阶段的执行结果
         */
        AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) {
            this.dep = dep; 
            this.fn = fn;
        }

        /**
         * 通常情况下getRawResult/setRawResult是用于设置其正常执行的结果,但由于这里是自定义ForkJoinTask任务,加上CompletableFuture中已经有成员属性来存储其结果,故两个方法暂时没用
         */
        public final Void getRawResult() { return null; }
        public final void setRawResult(Void v) {}

        /**
         * 默认情况下由ForkJoinPool来执行阶段,若是看过ForkJoinPool源码的同学应该知道该方法最终会被调用
         * @return 执行结果
         */
        public final boolean exec() { 
            run(); 
            return true; 
        }

        /**
         * 执行任务
         */
        public void run() {
            CompletableFuture<T> d; Supplier<T> f;
            if ((d = dep) != null && (f = fn) != null) {
                dep = null; fn = null;
                if (d.result == null) { // 判断是否执行完成
                    try {
                        d.completeValue(f.get()); // 设置执行结果
                    } catch (Throwable ex) {
                        d.completeThrowable(ex);
                    }
                }
                d.postComplete();
            }
        }
    }

    /**
     * 设置正常执行完成的结果
     * @param t 执行完成的结果
     * @return 结果值
     */
    final boolean completeValue(T t) {
        return UNSAFE.compareAndSwapObject(this, RESULT, null, (t == null) ? NIL : t);
    }

    /**
     * 设置异常执行完成的结果
     * @param x 异常信息
     * @return 结果值
     */
    final boolean completeThrowable(Throwable x) {
        return UNSAFE.compareAndSwapObject(this, RESULT, null, encodeThrowable(x));
    }

    /**
     * 包装异常信息
     * @param x 异常信息
     * @return 包装后的实例 
     */
    static AltResult encodeThrowable(Throwable x) {
        return new AltResult((x instanceof CompletionException) ? x : new CompletionException(x));
    }

    /**
     * 通知依赖阶段执行
     * 当阶段执行完毕后才会调用此方法
     */
    final void postComplete() {
        CompletableFuture<?> f = this; // 当前阶段
        Completion h; // 依赖当前阶段的步骤
        /**
         * 假设有阶段A、B,当前阶段是A,B依赖于A,A.stack = a1 -> a2 -> a3   B.stack = b1 -> b2 -> b3,a1步骤对应B阶段,a2、a3、b1、b2、b3没有依赖关系
         * 在A阶段执行完毕后,A.stack = b2 -> b1 -> a2 -> a3
         */
        while ((h = f.stack) != null || (f != this && (h = (f = this).stack) != null)) { // 由于在执行tryFire时会使f发生改变,所以当f.stack为空时说明并无依赖关系,使f重新指向A.stack去处理剩余的阶段
            CompletableFuture<?> d; Completion t; // d:步骤对应的阶段    t:下一个步骤      h:当前步骤
            if (f.casStack(h, t = h.next)) { // 更新stack指向下一个步骤
                if (t != null) { // 
                    if (f != this) { // f != this 说明f对应的阶段是B
                        pushStack(h); // 将B阶段的步骤放入到A阶段stack的第一个位置上
                        continue;
                    }
                    h.next = null;
                }
                /**
                 * 由于执行postComplete方法是在A阶段执行完毕之后才会调用,所以说其依赖阶段在正常情况下执行tryFire都会返回依赖阶段的实例,因为有可能另外的阶段依赖了实例,所以要接着判断stack
                 * 这里有一点需要注意的是,在依赖关系中,B阶段stack链表中的最后一个步骤可能会直接执行(没有依赖关系,若有依赖关系,则也会添加到A阶段stack链表中),而不会添加到A阶段stack链表中,这跟 t != null有关系
                 * 有些文章说是B阶段的所有步骤都会添加到A阶段中,愣是没看出来
                 */
                f = (d = h.tryFire(NESTED)) == null ? this : d;
            }
        }
    }

    /**
     * 异步执行任务,默认情况下的执行器是ForkJoinPool,即公共线程池
     * 每次调用该方法都会生成新的CompletableFuture对象,该方法与supplyAsync的区别就在于是否有执行结果值
     * @param runnable 任务
     * @return CompletableFuture新实例
     */
    public static CompletableFuture<Void> runAsync(Runnable runnable) {
        return asyncRunStage(asyncPool, runnable); // 该方法的执行过程与asyncSupplyStage是类似的,就不在贴出来了
    }

    /**
     * 使用指定执行器异步执行任务
     * @param runnable 任务
     * @param executor 指定执行器
     * @return CompletableFuture新实例
     */
    public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor) {
        return asyncRunStage(screenExecutor(executor), runnable);
    }

    /**
     * 设置执行结果
     * @param value 执行结果
     * @return CompletableFuture新实例
     */
    public static <U> CompletableFuture<U> completedFuture(U value) {
        return new CompletableFuture<U>((value == null) ? NIL : value);
    }

    /**
     * 任务是否执行完成,有可能是正常执行完成、异常执行完成、取消
     * @return 结果值
     */
    public boolean isDone() {
        return result != null;
    }

    /**
     * 获取执行结果
     * @return 结果值
     */
    public T get() throws InterruptedException, ExecutionException {
        Object r;
        return reportGet((r = result) == null ? waitingGet(true) : r); // 获取执行结果,若此时任务还未执行完成,则等待执行完成
    }

    /**
     * 获取执行结果,若是正常执行完成的话则返回执行结果,若是异常完成的话则抛出异常
     * @param r 执行结果
     * @return 执行结果或抛出异常
     */
    private static <T> T reportGet(Object r)
        throws InterruptedException, ExecutionException {
        if (r == null)
            throw new InterruptedException();
        if (r instanceof AltResult) {
            Throwable x, cause;
            if ((x = ((AltResult)r).ex) == null)
                return null;
            if (x instanceof CancellationException)
                throw (CancellationException)x;
            if ((x instanceof CompletionException) &&
                (cause = x.getCause()) != null)
                x = cause;
            throw new ExecutionException(x);
        }
        @SuppressWarnings("unchecked") T t = (T) r;
        return t;
    }

    /**
     * 使用自旋 + 阻塞的方式等待执行完成
     * @param interruptible 是否可中断的标识
     * @return 结果值或null
     */
    private Object waitingGet(boolean interruptible) {
        Signaller q = null;
        boolean queued = false;
        int spins = -1;
        Object r;
        while ((r = result) == null) {
            if (spins < 0)
                spins = (Runtime.getRuntime().availableProcessors() > 1) ?
                    1 << 8 : 0; // 多处理器情况下使用自旋
            else if (spins > 0) {
                if (ThreadLocalRandom.nextSecondarySeed() >= 0)
                    --spins;
            }
            else if (q == null)
                q = new Signaller(interruptible, 0L, 0L); // 用于记录等待执行完成的线程,同时也在执行完成后对其唤醒
            else if (!queued)
                queued = tryPushStack(q); // 将Signaller对象推入到stack上,也就是将该对象作为当前阶段的第一个步骤
            else if (interruptible && q.interruptControl < 0) { // q.interruptControl < 0 表示当前线程已发生中断
                q.thread = null;
                cleanStack(); // 清除所有步骤中已经被中断或执行完成的
                return null;
            }
            else if (q.thread != null && result == null) {
                try {
                    ForkJoinPool.managedBlock(q); // 阻塞当前线程
                } catch (InterruptedException ie) {
                    q.interruptControl = -1;
                }
            }
        }
        if (q != null) {
            q.thread = null;
            if (q.interruptControl < 0) { // q.interruptControl < 0 表示当前线程已经发生中断
                if (interruptible)
                    r = null;
                else
                    Thread.currentThread().interrupt();
            }
        }
        postComplete();
        return r;
    }

    /**
     * 获取执行结果,若未执行完成等待指定时间,若超过指定时间后还未执行完成则抛出异常
     * @param timeout 指定时间
     * @param unit 时间单位
     * @return 结果值
     */
    public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        Object r;
        long nanos = unit.toNanos(timeout);
        return reportGet((r = result) == null ? timedGet(nanos) : r); // timedGet方法与waitingGet类似,只不过没有加上自旋
    }

    /**
     * 获取执行结果,若此时任务还未执行完成,则等待执行完成
     * 外部调用get方法要加上try-catch,而该方法不用
     * @return 结果值
     */
    public T join() {
        Object r;
        return reportJoin((r = result) == null ? waitingGet(false) : r);
    }

    /**
     * 获取执行结果,此方法不会等待
     * 若执行完成则返回执行结果或抛出异常
     * 若执行未完成则返回valueIfAbsent
     * @param valueIfAbsent 指定值
     * @return 结果值
     */
    public T getNow(T valueIfAbsent) {
        Object r;
        return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
    }

    /**
     * 设置正常执行完成
     * @param value 执行结果
     * @return 结果值 
     */
    public boolean complete(T value) {
        boolean triggered = completeValue(value);
        postComplete();
        return triggered;
    }

    /**
     * 设置异常执行完成
     * @param ex 异常信息
     * @return 结果值
     */
    public boolean completeExceptionally(Throwable ex) {
        if (ex == null) throw new NullPointerException();
        boolean triggered = internalComplete(new AltResult(ex));
        postComplete();
        return triggered;
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果会被当前调用阶段的执行结果所影响
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 总结:等A阶段执行完毕,B阶段的执行结果是依赖A阶段的执行结果
     * @param fn 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn) {
        return uniApplyStage(null, fn);
    }

    /**
     * 异步执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果会被当前调用阶段的执行结果所影响
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 总结:等A阶段执行完毕,B阶段的执行结果是依赖A阶段的执行结果
     * @param fn 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn) {
        return uniApplyStage(asyncPool, fn);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容
     * @param e 执行器
     * @param f 步骤函数,指具体执行步骤的内容
     * @return 依赖阶段
     */
    private <V> CompletableFuture<V> uniApplyStage(Executor e, Function<? super T,? extends V> f) {
        if (f == null) 
            throw new NullPointerException();
        CompletableFuture<V> d =  new CompletableFuture<V>();
        if (e != null || !d.uniApply(this, f, null)) { // 若当前依赖阶段未能执行,则将依赖阶段的步骤推入到被依赖阶段的链条上
            UniApply<T,V> c = new UniApply<T,V>(e, d, this, f);
            push(c); // 将被依赖阶段的步骤放入到链表上
            c.tryFire(SYNC);  // 在一次尝试执行依赖阶段
        }
        return d; // 返回依赖阶段
    }

    /**
     * 执行当前依赖阶段的指定步骤内容
     * 调用此方法说明当前A阶段依赖其他B阶段,所以必须要先看看B阶段是否执行完成了,为了方便说明,将A称之为依赖阶段,B称之为被依赖阶段
     * @param a 被依赖阶段
     * @param f 步骤函数,指具体执行步骤的内容
     * @param c 步骤
     * @return 步骤是否执行完成
     */
    final <S> boolean uniApply(CompletableFuture<S> a, Function<? super S,? extends T> f, UniApply<S,T> c) {
        Object r; Throwable x;
        if (a == null || (r = a.result) == null || f == null) // 查看被依赖阶段是否执行完成了
            return false;
        tryComplete: if (result == null) { // 依赖阶段还未执行
            if (r instanceof AltResult) { // 判断被依赖阶段是否是异常执行完成,若是则当前依赖阶段将也是异常执行完成
                if ((x = ((AltResult)r).ex) != null) {
                    completeThrowable(x, r); // 当前依赖阶段也被设置成异常执行完成
                    break tryComplete;
                }
                r = null;
            }
            try {
                if (c != null && !c.claim()) // c.claim 判断当前步骤是否可以执行,有可能被取消了
                    return false;
                @SuppressWarnings("unchecked") S s = (S) r;
                completeValue(f.apply(s)); // 应用被依赖阶段的执行结果,执行依赖阶段的指定步骤内容
            } catch (Throwable ex) {
                completeThrowable(ex);
            }
        }
        return true;
    }

    @SuppressWarnings("serial")
    static final class UniApply<T,V> extends UniCompletion<T,V> {

        // 步骤函数,指具体执行步骤的内容
        Function<? super T,? extends V> fn;

        /**
         * 初始化
         * @param executor 执行器
         * @param dep 依赖阶段
         * @param src 被依赖阶段
         * @param fn 步骤函数,指具体执行步骤的内容
         */
        UniApply(Executor executor, CompletableFuture<V> dep, CompletableFuture<T> src, Function<? super T,? extends V> fn) {
            super(executor, dep, src); 
            this.fn = fn;
        }

        /**
         * 尝试执行步骤内容
         * @param mode 模式
         * @return 当前调用实例或null
         */
        final CompletableFuture<V> tryFire(int mode) {
            CompletableFuture<V> d; CompletableFuture<T> a;
            if ((d = dep) == null || !d.uniApply(a = src, fn, mode > 0 ? null : this)) // 尝试执行步骤内容
                return null;
            dep = null; src = null; fn = null;
            return d.postFire(a, mode); // 当前步骤执行完毕后通知其依赖阶段的执行,记住了,所谓的依赖阶段与被依赖阶段都是相对的
        }
    }

    @SuppressWarnings("serial")
    abstract static class UniCompletion<T,V> extends Completion {

        // 执行器
        Executor executor;

        // 依赖阶段
        CompletableFuture<V> dep; 

        // 被依赖阶段
        CompletableFuture<T> src; 

        /**
         * 初始化
         * @param executor 执行器
         * @param dep 依赖阶段
         * @param src 被依赖阶段
         * @param fn 步骤函数,指具体执行步骤的内容
         */
        UniCompletion(Executor executor, CompletableFuture<V> dep, CompletableFuture<T> src) {
            this.executor = executor; this.dep = dep; this.src = src;
        }

        /**
         * 判断当前步骤是否可以执行
         * @return 结果值
         */
        final boolean claim() {
            Executor e = executor;
            if (compareAndSetForkJoinTaskTag((short)0, (short)1)) {
                if (e == null)
                    return true;
                executor = null;
                e.execute(this);
            }
            return false;
        }

        /**
         * 判断当前步骤是否未执行
         * @return 结果值
         */
        final boolean isLive() { 
            return dep != null; 
        }
    }

    /**
     * 将指定步骤推入到当前阶段的第一个步骤
     * @param c 步骤
     */
    final void push(UniCompletion<?,?> c) {
        if (c != null) {
            while (result == null && !tryPushStack(c))
                lazySetNext(c, null);
        }
    }

    /**
     * 将指定步骤作为当前阶段的第一个步骤
     * @param c 步骤
     * @return 结果值
     */
    final boolean tryPushStack(Completion c) {
        Completion h = stack; // 获取当前阶段的第一个步骤
        lazySetNext(c, h); // 将当前阶段的第一个步骤与指定步骤进行关联
        return UNSAFE.compareAndSwapObject(this, STACK, h, c); // 指定步骤c将作为当前阶段的第一个步骤
    }

    /**
     * 关联步骤
     * @param c 上一个步骤
     * @param next 下一个步骤
     */
    static void lazySetNext(Completion c, Completion next) {
        UNSAFE.putOrderedObject(c, NEXT, next);
    }

    /**
     * 当前阶段已执行完毕了,需要去触发其依赖阶段的执行
     * 这里可能会有点绕,假设C依赖B,B依赖A,那么当A执行完毕后在触发B的执行,当B执行完毕后再触发C的执行,所以说所谓的依赖阶段与被依赖阶段都是相对的
     * @param a 被依赖阶段
     * @param mode 模式
     * @return 当前实例或null
     */
    final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
        if (a != null && a.stack != null) {
            if (mode < 0 || a.result == null)
                a.cleanStack();
            else
                a.postComplete(); // 触发其依赖阶段的执行
        }
        if (result != null && stack != null) {
            if (mode < 0)
                return this;
            else
                postComplete(); // 触发其依赖阶段的执行
        }
        return null;
    }

    // 很多相关方法与thenApply基本相同,就不贴代码了...

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果为null
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 总结:等A阶段执行完毕,B阶段的执行结果不依赖A阶段的执行结果,始终都是null,但是B阶段的执行过程需要A阶段的执行结果的参与
     * @param action 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
        return uniAcceptStage(null, action);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果为null
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 总结:等A阶段执行完毕,B阶段的执行结果不依赖A阶段的执行结果,始终都是null,B阶段的执行过程不需要A阶段的执行结果的参与
     * @param action 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public CompletableFuture<Void> thenRun(Runnable action) {
        return uniRunStage(null, action);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果会被当前调用阶段的执行结果所影响
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 多层依赖关系,相当于C依赖A,C依赖B
     * 总结:等AB阶段执行完毕,C阶段的执行结果依赖AB阶段的执行结果
     * @param other 依赖阶段
     * @param fn 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public <U,V> CompletableFuture<V> thenCombine(CompletionStage<? extends U> other, BiFunction<? super T,? super U,? extends V> fn) {
        return biApplyStage(null, other, fn);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果为null
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 多层依赖关系,相当于C依赖A,C依赖B
     * 总结:等AB阶段执行完毕,C阶段的执行结果不依赖AB阶段的执行结果,始终都是null,但是C阶段的执行过程需要AB阶段的执行结果的参与
     * @param other 依赖阶段
     * @param action 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T, ? super U> action) {
        return biAcceptStage(null, other, action);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果为null
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 多层依赖关系,相当于C依赖A,C依赖B
     * 总结:等AB阶段执行完毕,C阶段的执行结果不依赖AB阶段的执行结果,始终都是null,C阶段的执行过程不需要AB阶段的执行结果的参与
     * @param other 依赖阶段
     * @param action 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other, Runnable action) {
        return biRunStage(null, other, action);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果会被当前调用阶段的执行结果或另外的被依赖阶段所影响
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 多层依赖关系,相当于C依赖A,C依赖B
     * 总结:等AB阶段中任何一个执行完毕,C阶段的执行结果依赖AB阶段中任何一个的执行结果
     * @param other 依赖阶段
     * @param fn 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T, U> fn) {
        return orApplyStage(null, other, fn);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果为null
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 多层依赖关系,相当于C依赖A,C依赖B
     * 总结:等AB阶段中任何一个执行完毕,C阶段的执行结果不依赖AB阶段的执行结果,始终都是null,但是C阶段的执行过程需要AB阶段中任何一个的执行结果的参与
     * @param other 依赖阶段
     * @param action 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action) {
        return orAcceptStage(null, other, action);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果为null
     * 每次调用该方法都会生成新的CompletableFuture对象
     * 多层依赖关系,相当于C依赖A,C依赖B
     * 总结:等AB阶段中任何一个执行完毕,C阶段的执行结果不依赖AB阶段的执行结果,始终都是null,C阶段的执行过程不需要AB阶段的执行结果的参与
     * @param other 依赖阶段
     * @param action 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other, Runnable action) {
        return orRunStage(null, other, action);
    }

    /**
     * 执行当前依赖阶段的指定步骤内容,依赖阶段的执行结果会被当前调用阶段的执行结果所影响
     * fn函数会返回新的CompletableFuture对象,与thenCompse返回的对象不是同一个
     * 组合CompletableFuture,个人感觉与thenApply差不多一个样
     * 总结:等A阶段执行完毕,B阶段的执行结果依赖A阶段的执行结果
     * @param fn 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public <U> CompletableFuture<U> thenCompose(Function<? super T, ? extends CompletionStage<U>> fn) {
        return uniComposeStage(null, fn);
    }

    /**
     * 当调用阶段执行完成后运行指定动作,不管调用阶段是正常执行完成还是异常执行完成都会调用
     * 每次调用该方法都会生成新的CompletableFuture对象,该对象的执行结果与调用阶段的执行结果一样
     * @param action 指定动作
     * @return Completable新实例
     */
    public CompletableFuture<T> whenComplete(BiConsumer<? super T, ? super Throwable> action) {
        return uniWhenCompleteStage(null, action);
    }

    /**
     * 当调用阶段执行完成后运行指定动作,不管调用阶段是正常执行完成还是异常执行完成都会调用
     * 每次调用该方法都会生成新的CompletableFuture对象,该对象的执行结果受调用阶段的执行结果所影响
     * @param fn 步骤函数,指具体执行步骤的内容
     * @return Completable新实例
     */
    public <U> CompletableFuture<U> handle(BiFunction<? super T, Throwable, ? extends U> fn) {
        return uniHandleStage(null, fn);
    }

    /**
     * 等待指定多重依赖阶段全部执行完毕后才能执行当前阶段
     * @param cfs 指定多重依赖
     * @return Completable新实例
     */
    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
        return andTree(cfs, 0, cfs.length - 1);
    }

    /**
     * 调用此方法说明是一个阶段依赖多个阶段,而这多个阶段之间并没有依赖关系,这很关键
     * 由于依赖关系是通过回调来执行,它在多重依赖之间构建了多个虚拟依赖阶段,从而减少依赖阶段个数直到只有两个,这样子形成了二叉树,感觉讲的不是很明白,直接画吧
     * 假设 X -> [A,B,C,D,E,F,G]  表示X阶段依赖ABCDEFG,构建虚拟依赖阶段
     * 
     *                  X
     *            /            \
     *           T1            T2
     *        /     \       /     \ 
     *       Z1     Z2     Z3     Z4
     *      /  \   /  \   /  \   /
     *     A    B  C   D  E   F  G 
     *
     * 其之间的依赖关系就是一颗二叉树,要执行X阶段就要等T1、T2执行完成,要执行T1、T2就要等Z1、Z2、Z3、Z4执行完成,所以最终还是要等ABCDEFG执行完成
     *
     * @param cfs 指定多重依赖
     * @param lo 起始索引
     * @param hi 结束索引
     * @return Completable新实例
     */
    static CompletableFuture<Void> andTree(CompletableFuture<?>[] cfs, int lo, int hi) {
        CompletableFuture<Void> d = new CompletableFuture<Void>();
        if (lo > hi) // empty
            d.result = NIL;
        else {
            CompletableFuture<?> a, b;
            int mid = (lo + hi) >>> 1;
            if ((a = (lo == mid ? cfs[lo] : andTree(cfs, lo, mid))) == null ||
                (b = (lo == hi ? a : (hi == mid+1) ? cfs[hi] : andTree(cfs, mid+1, hi)))  == null)
                throw new NullPointerException();
            if (!d.biRelay(a, b)) {
                BiRelay<?,?> c = new BiRelay<>(d, a, b);
                a.bipush(b, c);
                c.tryFire(SYNC);
            }
        }
        return d;
    }

    /**
     * 等待指定多重依赖阶段中任何一个执行完毕后就可以执行当前阶段
     * @param cfs 指定多重依赖
     * @return Completable新实例
     */
    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
        return orTree(cfs, 0, cfs.length - 1);
    }

    /**
     * 取消当前调用阶段,前提是当前调用阶段还未执行
     * @param mayInterruptIfRunning 暂未使用
     * @return 是否取消成功
     */
    public boolean cancel(boolean mayInterruptIfRunning) {
        boolean cancelled = (result == null) && internalComplete(new AltResult(new CancellationException()));
        postComplete();
        return cancelled || isCancelled();
    }

使用示例

大致上看懂了CompletableFuture原理,基本上每个方法的原理都很类似,在概念上可能会容易混淆,最好是能有自己的理解,不过个人觉得其原理并不是重点,所以并没有很深入去分析,更多的是帮助读者能够清晰地知道每个方法的使用效果。CompletableFuture是一个工具类,方便开发者去执行计算,为了更方便使用,特意写了使用示例供参考,这份示例我也放在了github上-CompletableFuture使用示例


    // 方法上的注释可能会有所变扭,所以读者最好能够自己执行一遍方能理解其中的含义
    public class CompletableFutureTest {

    public static void main(String[] args) throws Exception{
        CompletableFutureTest completableFutureTest = new CompletableFutureTest();
//        completableFutureTest.testThenApply();
//        completableFutureTest.testThenAccept();
//        completableFutureTest.testThenRun();
//        completableFutureTest.testThenCombine();
//        completableFutureTest.testThenAcceptBoth();
//        completableFutureTest.testRunAfterBoth();
//        completableFutureTest.testApplyToEither();
//        completableFutureTest.testAcceptEither();
//        completableFutureTest.testRunAfterEither();
//        completableFutureTest.testThenCompose();
//        completableFutureTest.testWhenComplete();
//        completableFutureTest.testHandle();
//        completableFutureTest.testAllOf();
//        completableFutureTest.testAnyOf();
        completableFutureTest.testCancel();
    }

    /**
     *  异步执行,有执行结果
     */
    @SuppressWarnings("unused")
    private void testSupplyAsync() {
        CompletableFuture cf = CompletableFuture.supplyAsync(() -> {
            System.out.println("执行任务");
            return "1";
        });
    }

    /**
     * 异步执行,无执行结果
     */
    @SuppressWarnings("unused")
    private void testRunAsync() {
        CompletableFuture cf = CompletableFuture.runAsync(() -> System.out.println("执行任务"));
    }

    /**
     * 同步执行,阶段之间具有依赖关系使阶段的执行结果会有所依赖
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testThenApply() throws Exception{

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("Hello");

        // 此时的t对应的是cf的执行结果值,即t = Hello,此时completableFuture1的执行结果受cf的执行结果所影响
        CompletableFuture<String> completableFuture1 = cf.thenApply( t -> t + "World");
        System.out.println(completableFuture1.get());

        // 此时的t对应的是completableFuture1的执行结果,即Hello World,此时completableFuture2的执行结果受completableFuture1的执行结果所影响
        CompletableFuture completableFuture2 = completableFuture1.thenApply( t -> t + ", I love China");
        System.out.println(completableFuture2.get());
    }

    /**
     * 同步执行,即使阶段之间具有依赖关系,但每个阶段的执行结果都是null
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testThenAccept() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("Hello");

        // 此时的t对应的是cf的执行结果值,即t = Hello,但是completableFuture1的执行结果并不会被影响
        CompletableFuture completableFuture1 = cf.thenAccept( t -> System.out.println(t + "-执行任务"));
        System.out.println(completableFuture1.get());
    }

    /**
     * 同步执行,即使阶段之间具有依赖关系,但每个阶段的执行结果都是null,且不依赖其入参
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testThenRun() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("Hello");

        // 此时并无入参,但是要等cf执行完毕后才能执行该阶段
        CompletableFuture completableFuture1 = cf.thenRun(() -> System.out.println("执行任务"));

        System.out.println(completableFuture1.get());
    }

    /**
     * 同步执行,阶段之间具有多重依赖关系,使阶段的执行结果会有多重依赖
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testThenCombine() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("Hello");


        CompletableFuture<String> cf1 = new CompletableFuture<>();
        cf1.complete("World");

        // 此时t1代表cf的执行结果,t2代表cf1的执行结果,此时completableFuture的执行结果受cf、cf1的执行结果所影响
        CompletableFuture completableFuture = cf.thenCombine(cf1, (t1, t2) -> t1 + t2 + ", I love China");
        System.out.println(completableFuture.get());
    }

    /**
     * 同步执行,即使阶段之间具有多重依赖关系,但阶段的执行结果始终是null
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testThenAcceptBoth() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("1");

        CompletableFuture<String> cf1 = new CompletableFuture<>();
        cf1.complete("2");

        // 此时t1代表cf的执行结果,t2代表cf1的执行结果,但是cf2的执行结果始终都是null
        CompletableFuture cf2 = cf.thenAcceptBoth(cf1, (t1, t2) -> System.out.println(t1 + t2 + ", I love China"));
        System.out.println(cf2.get());
    }

    /**
     * 同步执行,即使阶段之间具有多重依赖关系,但每个阶段的执行结果都是null,且不依赖其入参
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testRunAfterBoth() throws Exception{

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("3");

        CompletableFuture<String> cf1 = new CompletableFuture<>();
        cf1.complete("4");

        CompletableFuture cf2 = cf.runAfterBoth(cf1, () -> System.out.println("I love China"));
        System.out.println(cf2.get());
    }

    /**
     * 同步执行,阶段之间具有依赖关系使阶段的执行结果会有所依赖
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testApplyToEither() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("5");

        CompletableFuture<String> cf1 = new CompletableFuture<>();
        cf1.complete("6");

        // 此时t有可能是cf或cf1,就看谁先执行完毕就用谁的
        CompletableFuture cf2 = cf.applyToEither(cf1, (t) -> t + ",I love China");
        System.out.println(cf2.get());
    }

    /**
     * 同步执行,即使阶段之间具有多重依赖关系,但阶段的执行结果始终是null
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testAcceptEither() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("7");

        CompletableFuture<String> cf1 = new CompletableFuture<>();
        cf1.complete("8");

        // 此时t有可能是cf或cf1,就看谁先执行完毕就用谁的
        CompletableFuture cf2 = cf.acceptEither(cf1, (t) -> System.out.println(t + ",I love China"));
        System.out.println(cf2.get());
    }

    /**
     * 同步执行,即使阶段之间具有多重依赖关系,但每个阶段的执行结果都是null,且不依赖其入参
     * 异步执行也是同理
     */
    @SuppressWarnings("unused")
    private void testRunAfterEither() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("9");

        CompletableFuture<String> cf1 = new CompletableFuture<>();
        cf1.complete("10");

        // 此时t有可能是cf或cf1,就看谁先执行完毕就用谁的
        CompletableFuture cf2 = cf.runAfterEither(cf1, () -> System.out.println("I love China"));
        System.out.println(cf2.get());
    }

    /**
     * 组合多个依赖
     */
    @SuppressWarnings("unused")
    private void testThenCompose() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("11");

        // 此时t是cf的执行结果
        CompletableFuture cf2 = cf.thenCompose((t) -> CompletableFuture.supplyAsync(() -> t + "执行thenCompse"));
        System.out.println(cf2.get());
    }

    /**
     * 当阶段执行完成后运行指定动作,其执行结果与调用阶段的执行结果一样
     */
    @SuppressWarnings("unused")
    private void testWhenComplete() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        CompletableFuture cf1 = cf.whenComplete((t, x) -> { // t代表cf正常的执行结果,x代表cf异常的执行结果
            System.out.println("正常执行的信息:" + t);
            System.out.println("异常执行的信息:" + x);
        });

//        cf.complete("执行完成");
        cf.completeExceptionally(new RuntimeException("异常执行"));
        System.out.println(cf1.get()); // cf1的执行结果就是cf的执行结果,若是正常执行的话就是一样的结果,若是异常执行的话get就会抛出异常
    }

    /**
     * 当阶段执行完成后运行指定动作,其执行结果由自身定义
     */
    @SuppressWarnings("unused")
    private void testHandle() throws Exception {

        CompletableFuture<String> cf = new CompletableFuture<>();
        CompletableFuture cf1 = cf.handle((t, x) -> { // t代表cf正常的执行结果,x代表cf异常的执行结果
            System.out.println("正常执行的信息:" + t);
            System.out.println("异常执行的信息:" + x);
            return "我的结果由我自己做主";
        });

        cf.complete("执行完成");
//        cf.completeExceptionally(new RuntimeException("异常执行"));
        System.out.println(cf1.get()); // cf1的执行结果由自己做主
    }

    /**
     * 等待指定多个阶段全部执行完毕后才能执行当前阶段,其执行结果始终都为null
     */
    @SuppressWarnings("unused")
    private void testAllOf() throws Exception {

        CompletableFuture<String> a = new CompletableFuture<>();
        a.complete("12");

        CompletableFuture<String> b = new CompletableFuture<>();
        b.complete("13");

        CompletableFuture<String> c = new CompletableFuture<>();
        c.complete("14");

        CompletableFuture<String> d = new CompletableFuture<>();
        d.complete("15");

        CompletableFuture<String> e = new CompletableFuture<>();
        e.complete("16");

        System.out.println(a.get());
        System.out.println(b.get());
        System.out.println(c.get());
        System.out.println(d.get());
        System.out.println(e.get());

        // 必须等待abcde执行完毕了才能执行,其执行结果始终为null
        CompletableFuture cf = CompletableFuture.allOf(a, b, c, d, e);
        System.out.println(cf.get());
    }

    /**
     * 等待指定多个阶段中任何一个执行完毕后就可以执行当前阶段,其执行结果与任何一个阶段执行完成的执行结果一样
     */
    @SuppressWarnings("unused")
    private void testAnyOf() throws Exception {

        CompletableFuture<String> a = new CompletableFuture<>();
//        a.complete("17");

        CompletableFuture<String> b = new CompletableFuture<>();
        b.complete("18");

        CompletableFuture<String> c = new CompletableFuture<>();
//        c.complete("19");

        CompletableFuture<String> d = new CompletableFuture<>();
//        d.complete("20");

        CompletableFuture<String> e = new CompletableFuture<>();
//        e.complete("21");


        // 等待指定多个阶段中任何一个执行完毕后才能执行,其执行结果与任何一个阶段执行完成的执行结果一样
        CompletableFuture cf = CompletableFuture.anyOf(a, b, c, d, e);
        System.out.println(cf.get());
    }

    /**
     * 取消当前调用阶段
     */
    @SuppressWarnings("unused")
    private void testCancel() {

        CompletableFuture<String> cf = new CompletableFuture<>();
        cf.complete("我已经执行完毕了");

        boolean result = cf.cancel(true);
        System.out.println(result);
    }
}

总结

CompletableFuture是一个提供快速计算的工具类,既然要使用它,那么肯定是对其方法的使用、效果有所掌握,这是关键,至于其原理个人觉得并不很重要,实际上也没啥原理...

posted @ 2020-12-20 20:21  zliawk  阅读(108)  评论(0)    收藏  举报