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行的执行步骤:
- base.complete("1")后base里的result属性会变成1
- 取base中stack(对象1)执行,出栈
- 取对象1中dep属性的stack(对象2)执行,出栈
- 取base中stack(对象3)执行,出栈
- 取对象3中dep属性的stack(对象4)执行,出栈
- 取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