What is the order in which multiple thenAccept blocks of a CompletableFuture are executed

喜夏-厌秋 提交于 2019-12-05 09:10:39

You are modelling the dependencies of completion stages by chaining them. If you chain two actions A and B to another action C, you define the relationships A → C and B → C, but no relationship between A and B and therefore, there is no relationship, including no ordering relationship, between them, in other words, you can’t even assume that one will run after the other, i.e.

CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    return "source";
});
base.thenAccept(s -> {
    System.out.println("entered first consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving first consumer");
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
base.thenAccept(s -> {
    System.out.println("entered second consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving second consumer");
});

will very likely print something like

entered first consumer in Thread[ForkJoinPool.commonPool-worker-1,5,main]
entered second consumer in Thread[main,5,main]
leaving second consumer
leaving first consumer

Though, of course, there is no guaranty about it.


To enforce your dependency between the two consumers, you have to chain them appropriately, e.g.

CompletableFuture<String> base=CompletableFuture.supplyAsync(() -> {
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
    return "source";
});
CompletableFuture<Void> next = base.thenAccept(s -> {
    System.out.println("entered first consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving first consumer");
});
LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(2));
base.thenAcceptBoth(next, (s,ignored) -> {
    System.out.println("entered second consumer in "+Thread.currentThread());
    LockSupport.parkNanos(TimeUnit.SECONDS.toNanos(1));
    System.out.println("leaving second consumer");
}).join();

Here, the second consumer is chained to base and next, to receive the result from base, but depend on next’s completion (which you normally wouldn’t require if there is no result to pass—maybe you want to rethink your design, if you have such a scenario).

Alternatively, you may convert the first Consumer to a Function which passes through the value, so you can chain it via thenApply, to allow chaining another thenAccept stage to it.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!