在编写Java CompletableFutures时使用哪个执行程序?

时间:2017-03-09 21:39:37

标签: java completable-future

我在某个存储库类上有一个返回CompletableFuture的方法。完成这些期货的代码使用阻止的第三方库。我打算有一个单独的有界Executor,这个存储库类将用它来进行这些阻塞调用。

以下是一个例子:

public class PersonRepository {
    private Executor executor = ...
    public CompletableFuture<Void> create(Person person) {...}
    public CompletableFuture<Boolean> delete(Person person) {...}
}

我的应用程序的其余部分将组成这些未来,并对结果做一些其他事情。当提供给thenAcceptthenComposewhenComplete等的其他函数时,我不希望它们在存储库的Executor上运行。

另一个例子:

public CompletableFuture<?> replacePerson(Person person) {
    final PersonRepository repo = getPersonRepository();
    return repo.delete(person)
        .thenAccept(existed -> {
            if (existed) System.out.println("Person deleted"));
            else System.out.println("Person did not exist"));
        })
        .thenCompose(unused -> {
            System.out.println("Creating person");
            return repo.create(person);
        })
        .whenComplete((unused, ex) -> {
            if (ex != null) System.out.println("Creating person");
            repo.close();
        });
}

JavaDoc声明:

  

为非异步方法的依赖完成提供的动作可以由完成当前CompletableFuture的线程执行,也可以由完成方法的任何其他调用者执行。

提问:为什么在这里?在什么情况下,还有另一个完成方法的调用者无法完成当前的未来?

主要问题:如果我希望所有println由与存储库使用的Executor不同的thenAccept执行,我需要将哪些方法设为异步并手动提供执行程序?

显然thenAcceptAsync需要更改为thenCompose,但我不确定这一点。

备选问题:哪个主题完成了从whenComplete返回的未来?

我的猜测是,无论线程完成从函数参数返回的未来是什么。换句话说,我还需要将whenCompleteAsync更改为ExecutionContext

也许我过度复杂化了,但这感觉好像很棘手。我需要非常关注所有这些未来的来源。同样从设计的角度来看,如果我回到未来,我如何阻止呼叫者使用我的执行者?感觉它破坏了封装。我知道Scala中的所有转换函数都采用隐式def FunctionA(): FunctionB() FunctionA() def FunctionB(): print("inside of B") FunctionB() ,这似乎解决了所有这些问题。

2 个答案:

答案 0 :(得分:5)

方面问题:如果您将中间CompletionStage分配给变量并在其上调用方法,它将在同一个线程上执行。

主要问题:只有第一个,所以将thenAccept更改为thenAcceptAsync - 以下所有内容将在用于接受的线程上执行其步骤。

备选问题:从thenCompose完成未来的主题与撰写时使用的相同。

您应该将CompletionStages视为在同一个线程上快速连续执行的步骤(通过按顺序应用函数),除非您特别希望使用异步在不同的线程上执行该步骤。接下来的所有步骤都是在新线程上完成的。

在您当前的设置中,步骤将按如下方式执行:

Thread-1: delete, accept, compose, complete

第一个接受异步,它变为:

Thread-1: delete
Thread-2: accept, compose, complete

关于你的上一个问题,如果他们添加了额外的步骤,你的呼叫者会使用相同的线程 - 我认为除了不返回CompletableFuture之外你还能做些什么,但是正常Future

答案 1 :(得分:4)

根据我的经验观察,执行这些非异步方法的线程将取决于首先发生的事件,thenCompose本身或Future背后的任务。

如果thenCompose首先完成(在您的情况下,几乎可以肯定),则该方法将在执行Future任务的同一线程上运行。

如果Future后面的任务首先完成,那么该方法将立即在调用线程上运行(即根本没有执行程序)。