Nice to meet you

关于CompletableFuture的一些个人理解

从CompletableFuture.supplyAsync 和 CompletableFuture.get入手

下面是supplyAsync的方法入口

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

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

可以看到,supplyAsync执行后是新建一个CompletableFuture对象,然后提交到指定的线程池中运行
现在看下实现Runnable方法的AsyncSupply类

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

run方法里有个主要的方法postComplete()
在子线程执行完成任务后,会通过postComplete()方法会调用tryFire()方法通知(唤醒: LockSupport.unpark(w))主线程

看下主线程在提交任务到线程池后在做啥,CompletableFuture.get()

    public T get() throws InterruptedException, ExecutionException {
        Object r;
        return reportGet((r = result) == null ? waitingGet(true) : r);
    }

get方法进来后如果子任务比较耗时还没结束 会进入waitingGet()方法

waitingGet方法里有个最重要的方法就是阻塞主线程,也就是ForkJoinPool.managedBlock(q)

如果是自定义的线程池就会走else,如果用的默认的jvm给的唯一线程池会走if,这里我们看else,因为如果要阻塞,都会走到blocker.block()
blocker是static final class Signaller extends Completion implements ForkJoinPool.ManagedBlocker

        public boolean block() {
            if (isReleasable())
                return true;
            else if (deadline == 0L)
                LockSupport.park(this);
            else if (nanos > 0L)
                LockSupport.parkNanos(this, nanos);
            return isReleasable();
        }

可以看到主线程的阻塞' LockSupport.park(this)'

简单总结,CompletableFuture.supplyAsync(Supplier<U> supplier,Executor executor)将任务提交给线程池进行异步处理,
直到该任务处理结束才会处理结果,结果值则是放在CompletableFuture的属性字段'volatile Object result;'的,并且会尝试唤醒
主线程(如果调用了CompletableFuture.get方法的话);
CompletableFuture.get()在主线程中则是第一次会去看下是否已经有任务的处理结果了,如果没有,则会阻塞自身,等待子线程将其唤醒

posted @ 2022-05-06 16:35  魏标  阅读(95)  评论(0编辑  收藏  举报