CompletableFuture实际操作的源码追究

本文深入探讨了Java的CompletableFuture类,从任务初始化、后续处理操作到内部类的功能,如AsyncSupply、UniAccept等。通过源码分析,揭示了CompletableFuture如何封装任务、处理异步结果以及构建任务依赖。同时,详述了各关键方法的作用,如supplyAsync、thenAccept、tryFire等,帮助读者理解并发编程中的复杂交互。

CompletableFuture实际操作的源码追究

在此之前整体框架:

  • Completion:封装了执行任务,以及该任务所依赖的其他任务的结果,在执行任务时进行不同的操作。
  • CompletableFuture:对任务结果的一些操作的封装,以及构建和处理Completion任务依赖的关系。

任务初始化:supplyAsync

    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(ASYNC_POOL, supplier);
    }

asyncSupplyStage方法

asyncSupplyStage方法会返回一个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;
    }

其实就是创建了一个AsyncSupply交由线程池进行异步处理。这里的AsyncSupply是一个ForkJoinTask,也是一个Completion

AsyncSupply类

    static final class AsyncSupply<T> extends ForkJoinTask<Void>
        implements Runnable, AsynchronousCompletionTask {
        CompletableFuture<T> dep; Supplier<? extends T> fn; // dep是本次任务的结果和有关依赖,fn是任务的执行逻辑
        AsyncSupply(CompletableFuture<T> dep, Supplier<? extends T> fn) {
            this.dep = dep; this.fn = fn;
        }

        public final Void getRawResult() { return null; }
        public final void setRawResult(Void v) {}
        public final boolean exec() { run(); return false; }

        public void run() {
            CompletableFuture<T> d; Supplier<? extends T> f;
            if ((d = dep) != null && (f = fn) != null) {
                dep = null; fn = null;
                if (d.result == null) {
                    try {
                        d.completeValue(f.get()); // <1>
                    } catch (Throwable ex) {
                        d.completeThrowable(ex);
                    }
                }
                d.postComplete();
            }
        }
    }

<1>执行任务fn.get,并将得到的结果封装到dep.resultresult会作为一个任务是否被执行过或是否完成的状态的判断。

后续处理操作:thenAccept

// CompletableFuture#thenAccept
public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
        return uniAcceptStage(null, action);
    }

    

uniAcceptStage方法

uniAcceptStage方法参数e如果是null就不会进行异步处理。

// CompletableFuture#uniAcceptStage
private CompletableFuture<Void> uniAcceptStage(Executor e,
                                                   Consumer<? super T> f) {
        if (f == null) throw new NullPointerException();
        Object r;
        if ((r = result) != null)
            return uniAcceptNow(r, e, f);
        CompletableFuture<Void> d = newIncompleteFuture();
        unipush(new UniAccept<T>(e, d, this, f));
        return d;
    }

// java.util.concurrent.CompletableFuture#unipush
    final void unipush(Completion c) {
        if (c != null) {
            while (!tryPushStack(c)) {
                if (result != null) {
                    NEXT.set(c, null);
                    break;
                }
            }
            if (result != null)
                c.tryFire(SYNC); // <2> 在UniAccept入栈的过程中,如果已经完成则以SYNC尝试执行。
        }
    }

thenAccept方法所依赖的CompletableFuture被完成执行uniAcceptNow方法,否则创建UniAccept,并将UniAccept这个任务添加到thenAccept方法所依赖的CompletableFutureCompetion栈中。

然后将新创建的CompletableFuture(对thenAccept方法的Consumer处理)返回。

uniAcceptNow方法

thenAccept方法所依赖的task已经执行完毕,在调用thenAccept方法的时候会进入到该方法。

 // CompletableFuture#uniAcceptNow 
      private CompletableFuture<Void> uniAcceptNow(
        Object r, Executor e, Consumer<? super T> f) { // r是当前CompletableFuture.result,e是传递进来的线程池,f是任务执行逻辑
        Throwable x;
          // Consumer的dep
        CompletableFuture<Void> d = newIncompleteFuture();
        if (r instanceof AltResult) {
            if ((x = ((AltResult)r).ex) != null) {
                d.result = encodeThrowable(x, r);
                return d;
            }
            r = null;
        }
        try {
            if (e != null) {
                e.execute(new UniAccept<T>(null, d, this, f)); // <1>
            } else {
                @SuppressWarnings("unchecked") T t = (T) r;
                f.accept(t); // <2>
                d.result = NIL;
            }
        } catch (Throwable ex) {
            d.result = encodeThrowable(ex);
        }
        return d;
    }
// CompletableFuture#newIncompleteFuture
    public <U> CompletableFuture<U> newIncompleteFuture() {
        return new CompletableFuture<U>();
    }

如果存在线程池则交由线程池执行Consumer,否则由当前线程执行Consumer

thenAccept返回的CompletableFuture中已经存在Consumer处理的结果。

UniAccept类

    static final class UniAccept<T> extends UniCompletion<T,Void> {
        Consumer<? super T> fn;
        // <1> 构造方法
        // executor:用来异步执行 fn 的线程池,
        // dep :对 fn 进行描述的 CompletableFutrue
        // src:fn 所依赖的 task 任务 ( src 的完成应该在fn之前)
        UniAccept(Executor executor, CompletableFuture<Void> dep,
                  CompletableFuture<T> src, Consumer<? super T> fn) {
            super(executor, dep, src); this.fn = fn;
        }
        final CompletableFuture<Void> tryFire(int mode) {
            CompletableFuture<Void> d; CompletableFuture<T> a;
            Object r; Throwable x; Consumer<? super T> f;
            if ((d = dep) == null || (f = fn) == null
                || (a = src) == null || (r = a.result) == null)
                return null;
            tryComplete: if (d.result == null) {
                if (r instanceof AltResult) {
                    if ((x = ((AltResult)r).ex) != null) {
                        d.completeThrowable(x, r);
                        break tryComplete;
                    }
                    r = null;
                }
                try {
                    if (mode <= 0 && !claim())
                        return null;
                    else {
                        @SuppressWarnings("unchecked") T t = (T) r;
                        f.accept(t);
                        d.completeNull();
                    }
                } catch (Throwable ex) {
                    d.completeThrowable(ex);
                }
            }
            dep = null; src = null; fn = null;
            return d.postFire(a, mode);
        }
    }

Completion类

所有的处理逻辑fnfn对应的结果CompletableFutrue,以及依赖fn的处理结果的其他任务(Completion)等信息,都会被封装成Completion的实现。

之前在supplyAsync方法中将Supplier封装成对应的Completion,然后交由线程池e.execute。那么就会触发Completion.run方法的执行。其实就是调用tryFire(ASYNC)方法。而tryFire方法的实现交由实现类完成。

    abstract static class Completion extends ForkJoinTask<Void>
        implements Runnable, AsynchronousCompletionTask {
        volatile Completion next;      // Treiber stack link

        /**
         * Performs completion action if triggered, returning a
         * dependent that may need propagation, if one exists.
         *
         * @param mode SYNC, ASYNC, or NESTED
         */
        abstract CompletableFuture<?> tryFire(int mode);

        /** Returns true if possibly still triggerable. Used by cleanStack. */
        abstract boolean isLive();

        public final void run()                { tryFire(ASYNC); }
        public final boolean exec()            { tryFire(ASYNC); return false; }
        public final Void getRawResult()       { return null; }
        public final void setRawResult(Void v) {}
    }

UniCompletion类

具有源CompletableFutrue、依赖CompletableFutrue以及线程池的Completion

    abstract static class UniCompletion<T,V> extends Completion {
        Executor executor;                 // executor to use (null if none)
        CompletableFuture<V> dep;          // the dependent to complete
        CompletableFuture<T> src;          // source for action

        UniCompletion(Executor executor, CompletableFuture<V> dep,
                      CompletableFuture<T> src) {
            this.executor = executor; this.dep = dep; this.src = src;
        }

        /**
         * Returns true if action can be run. Call only when known to
         * be triggerable. Uses FJ tag bit to ensure that only one
         * thread claims ownership.  If async, starts as task -- a
         * later call to tryFire will run action.
         */
        final boolean claim() { 
            Executor e = executor;
            if (compareAndSetForkJoinTaskTag((short)0, (short)1)) { // 保证只有一个线程执行
                if (e == null)
                    return true;
                executor = null; // disable
                e.execute(this);
            }
            return false;
        }

        final boolean isLive() { return dep != null; }
    }

claim方法

claim方法返回true,表示调用claim方法的线程可以执行fn逻辑处理。claim方法返回false,表示fn处理逻辑交由线程池异步处理,原调用线程不用处理了。

claim方法只有在tryFiremode<=0的时候才可以被调用。

tryFire在什么时候mode>0?那就是线程池通过run进而调用tryFire的时候(可以理解为tryFire被分配到线程池第一次被调用,已经在新线程中了,为什么还要多出来一个线程做无用功)。而mode<=0的时候原线程在调用Completion.postComplete方法做处理,异步处理已经可以执行的fn会提高效率。

isLive方法

表示当前Completion未经过get等方法获取结果。

postComplete方法

postComplete方法会在任务(Completion也是任务)完成对CompletableFuture.result设置之后由该taskCompletableFuture dep调用。而在dep中有一个Completion栈,是对当前处理结果有依赖关系的。postComplete方法就是在调用这些CompletiontryFire方法,进而让他们执行各自逻辑。(其他的Completion在完成处理之后也会在tryFire方法中调用,但是会根据传入的标识而终止递归)

// 将可执行的Completion从stack中弹出,并尝试触发。
// 只有在当前CompletableFuture被完成之后才可以进行操作
final void postComplete() {
    /*
     * On each step, variable f holds current dependents to pop
     * and run.  It is extended along only one path at a time,
     * pushing others to avoid unbounded recursion.
     */
    //在每一次循环中,f都是当前Completion stack的栈顶弹出的元素,
    // f会使用tryFire进行运行。它一次仅沿一条路径扩展,避免无限递归。
    CompletableFuture<?> f = this; Completion h;
    while ((h = f.stack) != null ||
           (f != this && (h = (f = this).stack) != null)) {
        CompletableFuture<?> d; Completion t;
        if (STACK.compareAndSet(f, h, t = h.next)) {
            if (t != null) {
                if (f != this) {
                    pushStack(h); // <2> 如果有一个tryFire返回不是null,会将其Completion栈中的元素放到当前栈首,然后在开始弹栈执行。
                    continue;
                }
                NEXT.compareAndSet(h, t, null); // try to detach
            }
            f = (d = h.tryFire(NESTED)) == null ? this : d; // <1>
        }
    }
}

postComplete会尝试执行当前stackCompletion任务。接着在tryFire方法中进行相关执行和处理操作。

<2>可能是应为此时传入的mode=-1,但是没有异步执行,在调用其postFire的时候直接返回this的情况。

tryFire方法

tryFire方法根据策略模式,其实就是根据当前Completion依赖的其他任务的结果(CompletableFutrue)进行相应的逻辑处理。

UniAccept#tryFire

Completion.dep.result是否为null是判断Completion是否被执行过的唯一标识,只能被执行过一次。

// CompletableFuture.UniAccept#tryFire
        final CompletableFuture<Void> tryFire(int mode) {
            CompletableFuture<Void> d; CompletableFuture<T> a;
            Object r; Throwable x; Consumer<? super T> f;
            // <1> 因为当前Completion依赖 src.result,所以无法继续处理会直接返回null
            if ((d = dep) == null || (f = fn) == null
                || (a = src) == null || (r = a.result) == null)
                return null;
            tryComplete: if (d.result == null) {
                if (r instanceof AltResult) {
                    if ((x = ((AltResult)r).ex) != null) {
                        d.completeThrowable(x, r);
                        break tryComplete;
                    }
                    r = null;
                }
                try {
                    if (mode <= 0 && !claim()) // <2>
                        return null;
                    else {
                        @SuppressWarnings("unchecked") T t = (T) r;
                        f.accept(t);
                        d.completeNull();
                    }
                } catch (Throwable ex) {
                    d.completeThrowable(ex);
                }
            }
            dep = null; src = null; fn = null;
            return d.postFire(a, mode);
        }

如果在处理逻辑fn被执行之前,所依赖的CompletableFutrue.result已经被赋值,对于thenAccept方法来说,那么就会在执行该方法的线程执行fn。这中情况不可能被调用tryFire,因为根本就没有产生异步任务Completion

在非上边的前提下,tryFire有两种被调用的可能:

  • 1):在Completion被线程池执行run方法的时候会以mode=1的状态被调用。

    CompletableFutrue.result==null:直接返回null,等待被情况2调用。

  • 2):在所依赖的CompletableFutre.resultCompletion a在线程池某个线程A完成赋值。会由A线程调用a.postComplete的时候以mode=-1的形式触发。

    不存在CompletableFutrue.result==null的情况,所以会经过判断执行CompletableFuture.UniCompletion#claim方法。如果claimf方法返回true,就需要当前线程自行执行fn处理。

postFire

postFire是在CompletableFutrue.result完成赋值之后执行的。也就是说之后当前Completion c执行结束之后,才会通过postComplete方法先去执行c所依赖的CompletableFutrueCompletion栈,再去执行cCompletableFutrue中保存的依赖c的结果的Completion栈。这个是建立在mode>=0的前提的,否则会将this返回。(即tryFire是以异步的形式调用的,或者是同步的形式调用的,而不是在依赖结果执行完毕之后被动调用。不然会直接返回this,追溯到tryFire被调用)

 // CompletableFuture#postFire(java.util.concurrent.CompletableFuture<?>, int)
   final CompletableFuture<T> postFire(CompletableFuture<?> a, int mode) {
       // a 是 this 所依赖的 结果 CompletableFutrue
        if (a != null && a.stack != null) {
            Object r;
            if ((r = a.result) == null)
                a.cleanStack();
            if (mode >= 0 && (r != null || a.result != null))
                a.postComplete();
        }
        if (result != null && stack != null) {
            if (mode < 0)
                return this;
            else
                postComplete();
        }
        return null;
    }
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值