• 响应式编程2----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
    ";
            }, 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
    ";
            }, 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
    ";
            }, 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
    ";
            }, 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
    ";
            }, 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
    ";
            }, 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
    ";
            }, 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
    ";
            }, 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

  • 相关阅读:
    /etc/vim/vimrc的一个的配置
    vim上下左右键输出A B
    数据结构-栈的实现之行编译器核心实现
    数据结构-栈的实现之括号匹配检测
    数据结构-栈的实现之数制转换
    数据结构-线性表的链式结构
    数据结构-栈的顺序结构两种方式
    简介
    数据结构-线性表的顺序结构
    NHibernate系列文章十六:使用程序集管理NHibernate项目(附程序下载)
  • 原文地址:https://www.cnblogs.com/yangshixiong/p/13399657.html
Copyright © 2020-2023  润新知