响应式编程----CompletableFuture详解

completableFuture是java8之后引入的特性,也就是我们可以异步执行相关操作,并根据这个未来会到来的结果去进行操作。感觉跟js中的promise差不多。

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

可以看出这个接口实现了future以及completionStage接口

future

当看到工作线程结果并非立马就要的话,可以交给Future,然后主线程可以在这期间做一些其他事情,当需要工作线程结果时,使用get()方法进行获取。get方法是阻塞的,也就是当你的工作线程并没有完成时,主线程会等待结果。future无法表达任务之间的依赖关系。

 CompletableStage

CompletableStage用来表示一步过程中的一个阶段,可以在另一个CompletableStage完成时做一些操作或者计算,此接口中定义了一些基本的行为,通过这些行为可以简洁的描述非常复杂的任务

 常用方法:

  • thenApply    将上一个stage的结果转化成新的类型或值
  • thenAccept     将上一个stage的结果进行消耗无返回值
  • thenRun       有上一个stage结果后,执行一段新的操作
  • thenCombine    结合两个stage的结果,转化成新的类型或值
  • thenCompose   返回一个新的completableStage,并将上一个stage的结果作为新的stage的supplier
  • exceptionally     当处理过程中遇到异常时进行的补偿处理
  • handle       统一对正常结果和异常结果的处理                  

大部分方法都有一aysnc结果的,表示异步,如果不传递就是用默认线程池;

completableFuture

completableFuture大致可以分为三种情况:

不带Aysnc方法:同步方法

带Async方法,只有一个参数:异步方法,使用默认的ForkJoinPool.commonPool获取线程池

带Aysnc方法,有两个参数:异步方法,切使用第二个参数指定的ExecutorService线程池

简单使用 

        // just get the result
        CompletableFuture<String> future = CompletableFuture.completedFuture("completed");
        System.out.println(future.get());  //completed

        // init complete and get
        CompletableFuture<Object> objectCompletableFuture = new CompletableFuture<>();
        System.out.println("start the thread to complete ie");
        System.out.println(Thread.currentThread());
        new Thread(() -> {
            System.out.println("will finish in 1s");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread());
            System.out.println("finished");
            objectCompletableFuture.complete("finish");
        }).start();
        System.out.println("start to get the result");
        System.out.println(objectCompletableFuture.get());
        /*
        result
            completed
            start the thread to complete ie
            Thread[main,5,main]
            start to get the result
            will finish in 1s
            Thread[Thread-0,5,main]
            finished
            finish
         */

        // exception
        CompletableFuture<Object> base = new CompletableFuture<>();
        base.completeExceptionally(new RuntimeException("error"));
        System.out.println(base.get());
        /*
            Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.RuntimeException: error
                at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:395)
                at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1999)
                at com.yang.completableFuture.CompletableFutureDemo.main(CompletableFutureDemo.java:51)
            Caused by: java.lang.RuntimeException: error
                at com.yang.completableFuture.CompletableFutureDemo.main(CompletableFutureDemo.java:50)
         */

常用创建CompletableFuture方法

// 比较特殊,入参就是返回值,也就是说可以用来执行需要其他返回值的异步任务。
public static <U> CompletableFuture<U> completedFuture(U value)

// 无返回值,使用默认线程池
public static CompletableFuture<Void> runAsync(Runnable runnable)

// 无返回值,使用自定义线程池
public static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)

// 有返回值,使用默认线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier)

// 有返回值,使用自定义线程池
public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier, Executor executor)

// 无返回值,传入的所有对象执行完毕后,会返回一个新的CompletableFuture,如果有异常,会返回空
public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)

执行任务完成之后,可以对结果进行额外操作

whenComplete

BiConsumer<T,U> 函数接口有两个参数,无返回值。
Function<T,R> 函数接口有一个输入参数,返回一个结果。

// Async,同步处理正常计算结果或异常,使用执行任务的线程来执行该方法
public CompletableFuture<T> whenComplete(BiConsumer<? super T,? super Throwable> action)
// Async,异步处理正常计算结果或异常,使用执行任务的那个线程池中的线程来执行该方法!
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? super Throwable> action)
// Async,异步处理正常计算结果或异常,使用自定义线程池来执行该方法
public CompletableFuture<T> whenCompleteAsync(BiConsumer<? super T,? superThrowable> action, Executor executor)
// 处理异常。
public CompletableFuture<T> exceptionally(Function<Throwable,? extends T> fn)

示例:

public static int mockTask(){
        System.out.println("start task");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("the mock task thread:" + Thread.currentThread().getId());
        System.out.println("task is end");
        return new Random().nextInt();
    }

    public static void sync() throws ExecutionException, InterruptedException {
        ForkJoinPool forkJoinPool = new ForkJoinPool(10);
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(WhenComplete::mockTask, forkJoinPool);
        CompletableFuture<Integer> completableFuture = future.whenComplete((result, exception) -> {
            System.out.println("the when complete use thread" + Thread.currentThread().getId());
            System.out.println("the result is :" + result);
            System.out.println("teh exception is : {}" + (exception == null ? "no error" : exception));
        });
        System.out.println("the main use thread" + Thread.currentThread().getId());

        System.out.println("the future result is:" + future.get());
        System.out.println("the completableFuture result is:" + completableFuture.get());
        /*
            start task
            the main use thread1
            the mock task thread:13
            task is end
            the when complete use thread13
            the result is :87831413
            the future result is:87831413
            teh exception is : {}no error
            the completableFuture result is:87831413
         */
    }

    public static void async() throws ExecutionException, InterruptedException {
        ForkJoinPool forkJoinPool = new ForkJoinPool(10);

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(WhenComplete::mockTask, forkJoinPool);
        CompletableFuture<Integer> completableFuture = future.whenCompleteAsync((result, exception) -> {
            System.out.println("the when complete use thread" + Thread.currentThread().getId());
            System.out.println("the result is :" + result);
            System.out.println("teh exception is : {}" + (exception == null ? "no error" : exception));
        });
        System.out.println("the main use thread" + Thread.currentThread().getId());

        System.out.println("the future result is:" + future.get());
        System.out.println("the completableFuture result is:" + completableFuture.get());
        /*
            start task
            the main use thread1
            the mock task thread:13
            task is end
            the when complete use thread14
            the result is :696707836
            the future result is:696707836
            teh exception is : {}no error
            the completableFuture result is:696707836
         */
    }

从上述输出结果可以看出,whenComplete是使用处理任务的工线程继续处理,也就是同步的,whenCompleteAsync是另外其一个线程进行处理的,在进行任务是,需要自己注入一个线程池,否则使用默认线程池,上述逻辑只会有两个激活的线程,无法看出区别。

exceptionally

    public static void exception() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(WhenComplete::throwException);
        CompletableFuture<Integer> completableFuture = future.whenCompleteAsync((result, exception) -> {
            System.out.println("the result is :" + result);
            System.out.println("teh exception is : {}" + (exception == null ? "no error" : exception));
        });
        completableFuture.exceptionally(exception -> {
            System.out.println("cache the exception " + exception);
            return 0;
        });
        System.out.println("the future result is:" + future.get());
        System.out.println("the completableFuture result is:" + completableFuture.get());
        /*
            start to throw the exception
         */
    }

    public static void exception2() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(WhenComplete::throwException);
        CompletableFuture<Integer> completableFuture = future.whenCompleteAsync((result, exception) -> {
            System.out.println("the result is :" + result);
            System.out.println("teh exception is : {}" + (exception == null ? "no error" : exception));
        });
        completableFuture.exceptionally(exception -> {
            System.out.println("cache the exception " + exception);
            return 0;
        });
        System.out.println("the completableFuture result is:" + completableFuture.get());
        /*
            start to throw the exception
            the result is :null
            teh exception is : {}java.util.concurrent.CompletionException: java.lang.RuntimeException: error
            cache the exception java.util.concurrent.CompletionException: java.lang.RuntimeException: error
         */
    }

    public static void exception3() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(WhenComplete::throwException);
        CompletableFuture<Integer> completableFuture = future.whenCompleteAsync((result, exception) -> {
            System.out.println("the result is :" + result);
            System.out.println("teh exception is : {}" + (exception == null ? "no error" : exception));
        });
        CompletableFuture<Integer> exceptionally = completableFuture.exceptionally(exception -> {
            System.out.println("cache the exception " + exception);
            return 0;
        });
        System.out.println("the completableFuture result is:" + completableFuture.get());
        System.out.println("the exceptionally result is:" + exceptionally.get());
        /*
            start to throw the exception
            the result is :null
            teh exception is : {}java.util.concurrent.CompletionException: java.lang.RuntimeException: error
            cache the exception java.util.concurrent.CompletionException: java.lang.RuntimeException: error
         */
    }

    public static void exception4() throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(WhenComplete::throwException);
        CompletableFuture<Integer> completableFuture = future.whenCompleteAsync((result, exception) -> {
            System.out.println("the result is :" + result);
            System.out.println("teh exception is : {}" + (exception == null ? "no error" : exception));
        });
        CompletableFuture<Integer> exceptionally = completableFuture.exceptionally(exception -> {
            System.out.println("cache the exception " + exception);
            return 0;
        });
        System.out.println("the exceptionally result is:" + exceptionally.get());
        /*
            start to throw the exception
            the result is :null
            teh exception is : {}java.util.concurrent.CompletionException: java.lang.RuntimeException: error
            cache the exception java.util.concurrent.CompletionException: java.lang.RuntimeException: error
            the exceptionally result is:0
         */
    }

从上述四个实例可以看出,exceptionally是捕捉异常,他会在whenComplete方法之后执行,如果去获取已经发生异常的CompletableFuture对象,会直接抛出错误,但是经过exceptionally捕捉之后并返回值,会构建一个新的CompletableFuture对象,这个对象的值就是返回值。

handle

方法

//同步
public <U> CompletableFuture<U> handle(BiFunction<? super T,Throwable,? extends U> fn)
//异步,使用原始CompletableFuture的线程
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn)
//异步,使用自定义线程池的线程
public <U> CompletableFuture<U> handleAsync(BiFunction<? super T,Throwable,? extends U> fn, Executor executor)

示例:

public static int mockTask(){
        System.out.println("start task");
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("task is end");
        return new Random().nextInt();
    }

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(Handle::mockTask);
        CompletableFuture<Integer> future1 = future.handleAsync((result, exception) -> {
            System.out.println("the result: " + result);
            System.out.println("the error: " + (exception == null ? "no error" : exception));
            return result * 10;
        });

        System.out.println("the future result: " + future.get() );
        System.out.println("the future1 result: " + future1.get() );
        /*
            start task
            task is end
            the future result: 1544126383
            the result: 1544126383
            the error: no error
            the future1 result: -1738605354
         */
    }

handle方法就是在任务执行完毕之后,执行该方法逻辑,这个对象内部方式是需要有返回值,并且返回的对象的值就是这个方法的返回值。

thenRun

方法

// 同步
public CompletableFuture<Void> thenRun(Runnable action)
// 异步
public CompletableFuture<Void> thenRunAsync(Runnable action)
// 异步
public CompletableFuture<Void> thenRunAsync(Runnable action, Executor executor)

示例

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100);
        CompletableFuture<Void> future1 = future.thenRun(() -> {
            System.out.println("run able");
        });
        System.out.println("future: " + future.get());
        System.out.println("future1: " + future1.get());
        /*
            run able
            future: 100
            future1: null
         */
    }

这个方法不消费CompletableFuture的结果,而是执行下一个任务

thenApply

方法

// 同步
public <U> CompletableFuture<U> thenApply(Function<? super T,? extends U> fn)
//异步
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn)
// 异步
public <U> CompletableFuture<U> thenApplyAsync(Function<? super T,? extends U> fn, Executor executor)

示例

CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1).thenApply(i -> i * 2).thenApply(i -> i * 2);
System.out.println(future.get()); // 4

thenApply方法跟handle有点类似,都可以改变对象的返回结果,但不同的是handle可以捕捉异常,thenApply相当于把CompleteableFuture一个一个的连接起来,并把上一个对象的结果传给下一个对象

thenAccept

方法

// 同步
public CompletableFuture<Void> thenAccept(Consumer<? super T> action)
// 异步
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action)
// 异步
public CompletableFuture<Void> thenAcceptAsync(Consumer<? super T> action, Executor executor)

示例:

        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 1);
        CompletableFuture<Void> future1 = future.thenAcceptAsync(i -> {
            System.out.println("result: " + i);
        });
        System.out.println("future: " + future.get());
        System.out.println("future1: " + future1.get());
        /*
            result: 1
            future: 1
            future1: null
         */

这个方法就是一个消费消息,无返回值,我们可以看到接受的参数就是Consumer

thenAcceptBoth

// 同步
public <U> CompletableFuture<Void> thenAcceptBoth(CompletionStage<? extends U> other, BiConsumer<? super T,? super U> action)
// 异步
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T,? super U> action)
// 异步
public <U> CompletableFuture<Void> thenAcceptBothAsync(CompletionStage<? extends U> other, BiConsumer<? super T,? super U> action, Executor executor)

示例

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100);
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> 200);
        CompletableFuture<Void> future2 = future.thenAcceptBoth(future1, (x, y) -> {
            System.out.println("the x : " + x);
            System.out.println("the y : " + y);
        });
        System.out.println("future: " + future.get());
        System.out.println("future1: " + future1.get());
        System.out.println("future2: " + future2.get());
        /*
            the x : 100
            the y : 200
            future: 100
            future1: 200
            future2: null
         */
    }

action就是bigConsumer,纯消费的,这个方法会把两个CompletableFuture对象的值结合起来,并接受,无返回值

runAfterBoth

方法

//runAfterBoth和上面三个的区别就是它不消费原始的CompletableFuture结果
public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,  Runnable action)。

示例

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100);
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("start sleep");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end sleep");
            return 200;
        });
        future.runAfterBoth(future1, () ->{
            System.out.println("over, but no args");
        });
        System.out.println("future: " + future.get());
        System.out.println("future1: " + future1.get());
        /*
            start sleep
            future: 100
            end sleep
            over, but no args
            future1: 200        
         */
    }

从上述结果可以看出,这个方法会等待两个对象都执行完毕,会执行,但是并不接收参数

acceptEither

方法

public CompletableFuture<Void> acceptEither(CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action)
public CompletableFuture<Void> acceptEitherAsync(CompletionStage<? extends T> other, Consumer<? super T> action, Executor executor)

示例

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100);
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("start sleep");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end sleep");
            return 200;
        });
        future.acceptEither(future1, (x) ->{
            System.out.println("the result: " + x);
        });
        System.out.println("future: " + future.get());
        System.out.println("future1: " + future1.get());
        /*
            run able
            future: 100
            future1: null
         */
    }

从结果可以看出,当任意一个CompletableFuture执行完毕就会执行,并且没有返回值

applyToEither

方法

public <U> CompletableFuture<U> applyToEither(CompletionStage<? extends T> other, Function<? super T,U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn)
public <U> CompletableFuture<U> applyToEitherAsync(CompletionStage<? extends T> other, Function<? super T,U> fn, Executor executor)

示例

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> 100);
        CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
            System.out.println("start sleep");
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("end sleep");
            return 200;
        });
        CompletableFuture<Integer> future2 = future.applyToEither(future1, (x) -> {
            System.out.println("the result: " + x);
            return 1000;
        });
        System.out.println("future: " + future.get());
        System.out.println("future2: " + future2.get());
        System.out.println("future1: " + future1.get());
        /*
            start sleep
            the result: 100
            future: 100
            future2: 1000
            end sleep
            future1: 200
         */
    }

从上述代码可以看出只要任意一个CompletalbeFuture对象完成,就会执行方法,并且有返回值,注意打印顺序

anyof/allof

方法

public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs)
public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs)

示例

public static void all(){
        Random random = new Random();

        ForkJoinPool forkJoinPool = new ForkJoinPool(10);

        long start = System.currentTimeMillis();
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("all product detail");
            return "all product detail\n";
        }, forkJoinPool);

        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("all seller info");
            return "all seller info\n";
        }, forkJoinPool);

        CompletableFuture<String> futureC = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("all stock");
            return "all stock\n";
        }, forkJoinPool);

        CompletableFuture<String> futureD = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("all order");
            return "all order\n";
        }, forkJoinPool);

        CompletableFuture<Void> allFuture = CompletableFuture.allOf(futureA, futureB, futureC, futureD);
        allFuture.join();
        System.out.println("all use time:" + (System.currentTimeMillis() - start));
    }

    public static void main(String[] args) {
        all();
        any();
        /*
            all seller info
            all product detail
            all order
            all stock
            all use time:1790
            any order
            any: any order
            any use time:1194
         */
    }

    public static void any(){
        Random random = new Random();

        ForkJoinPool forkJoinPool = new ForkJoinPool(10);

        long start = System.currentTimeMillis();
        CompletableFuture<String> futureA = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("any product detail");
            return "any product detail\n";
        }, forkJoinPool);

        CompletableFuture<String> futureB = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("any seller info");
            return "any seller info\n";
        }, forkJoinPool);

        CompletableFuture<String> futureC = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("any stock");
            return "any stock\n";
        }, forkJoinPool);

        CompletableFuture<String> futureD = CompletableFuture.supplyAsync(() -> {
            try {
                Thread.sleep(1000 + random.nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("any order");
            return "any order\n";
        }, forkJoinPool);
        CompletableFuture<Object> anyFuture = CompletableFuture.anyOf(futureA, futureB, futureC, futureD);
        System.out.println("any: " + anyFuture.join());
        System.out.println("any use time:" + (System.currentTimeMillis() - start));
    }

从上述代码运行结果可以知道,allof会等待所有方法执行完毕,并且无返回值,anyof会等到最快执行的那个方法执行完毕,并且接受最快执行的的那个方法的返回值

任务的依赖关系

    static void executeBase() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> base = new CompletableFuture<>();
        CompletableFuture<String> future = base.thenApply(s -> s + "2").thenApply(s -> s + "3");
        base.complete("1");
        System.out.println(future.get());  // 123
    }

    static void executeFuture() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> base = new CompletableFuture<>();
        CompletableFuture<String> future = base.thenApply(s -> s + "2").thenApply(s -> s + "3");
        future.complete("1");
        System.out.println(future.get());  // 1
    }

    static void printBase() throws ExecutionException, InterruptedException {
        CompletableFuture<Object> base = new CompletableFuture<>();
        CompletableFuture<String> future = base.thenApply(s -> s + "2").thenApply(s -> s + "3");
        future.complete("1");
        System.out.println(base.get());  // the thread will be block
    }


    public static void main(String[] args) throws ExecutionException, InterruptedException {
        executeBase();
        executeFuture();
        printBase();
    }

从上述可以简单得出结论,completableFuture是依靠complete来进行驱动,如果没有complete,那么不会执行后续代码。

另外执行base的complete与future的complete的返回结果不同,分析一下源码:

 

首先这里面有两个比较重要的属性,一个是Completion对象stack,这是一个CAS((Compare-and-Swap),即比较并替换,是一种实现并发算法时常用到的技术在并发程序中,如果多个线程共享一个变量,通过CAS可以在不加锁的情况下实现对共享变量的安全的访问)实现的无锁并发栈,每个链式调用的任务都会被压入这个栈,stack会永远指向栈顶,另外一个就是object对象,这个就是当前CompletableFuture的结果

接下来看一下Completion

 其中属性next保存了栈中下一个元素的引用

 接下来看一下thenAply的引用,可以看到这里面调用uniApplyStage方法,如果同步调用,就不传递线程池,异步调用就传递默认线程是或者调用方传递的线程池

接下来进入uniApplyStage,从截图可以看出,如果当前CompletableFuture有结果会进入uniApplyNow

 接下来先进入uniApplyNow

 另外一种情况就是这个result为空就会进入unipush, 将这个completion放入栈,NEXT.set就是之前说的CAS压栈

tryFire是一个abstract方法,接下来看一下uniApply中的实现,其实跟之前uniApplyNow类似,先判断异常,然后进入执行,completeValue也是考略线程安全放入结果

 当然如果值不为空,那会进入下述方法,如果栈为空,name返回空

 

 进入postComplete

 调用内部执行步骤

一个教程:

CompletableFuture<String> base = new CompletableFuture<>();
CompletableFuture<String> future =
    base.thenApply(
        s -> {
            log.info("2");
            return s + " 2";
        });
base.thenAccept(s -> log.info(s+"a")).thenAccept(aVoid -> log.info("b"));
base.thenAccept(s -> log.info(s+"c")).thenAccept(aVoid -> log.info("d"));
base.complete("1");
log.info("base result: {}", base.get());
log.info("future result: {}", future.get());

 

第八行

 

第九行后

至此,整个对象关系如同一个执行计划,等待着base的complete那一刻。

我们再来分解下第10行的执行步骤:

  1. base.complete("1")后base里的result属性会变成1
  2. 取base中stack(对象1)执行,出栈
  3. 取对象1中dep属性的stack(对象2)执行,出栈
  4. 取base中stack(对象3)执行,出栈
  5. 取对象3中dep属性的stack(对象4)执行,出栈
  6. 取base中stack(对象5)执行,出栈

base的stack(对象2、1、0)和它下面那些dep中的stack执行上顺序正好是相反的,暂且称base的stack为主stack吧,我们来画一张更通用的关系来重点看下stack:

先执行base的栈顶Completion 2,成功后出栈。然后会检查Completion 2中dep的stack,只要没到栈底,则会取出栈顶压入base的stack中,该图则把Completion 8、7分别压到base的stack中,然后执行栈底的Completion 6

重复这个过程,执行base的栈顶Completion 7,由于Completion 7的dep的stack为空,则直接出栈即可。接着Completion 8会被执行。

接下来处理Completion 1的过程和之前类似。

最终的执行顺序是base,2,6,7,8,1,3,4,5,0

猜你喜欢

转载自www.cnblogs.com/yangshixiong/p/13399657.html