Qual executor é usado ao compor o Java CompletableFutures?

Eu tenho um método em alguma classe de repositório que retorna umCompletableFuture. O código que completa esses futuros usa uma biblioteca de terceiros que bloqueia. Eu pretendo ter um limite separadoExecutor qual esta classe de repositório usará para fazer essas chamadas de bloqueio.

Aqui está um exemplo:

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

O restante da minha inscrição comporá esses futuros e fará outras coisas com os resultados. Quando essas outras funções fornecidas aothenAccept, thenCompose, whenComplete, etc, não quero que eles sejam executados noExecutor para o repositório.

Outro exemplo:

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();
        });
}

O JavaDoc declara:

As ações fornecidas para conclusões dependentes de métodos não assíncronos podem ser executadas pelo encadeamento que conclui o CompletableFuture atual ou por qualquer outro responsável pela chamada de um método de conclusão.

Pergunta secundária: Por que existe umou aqui? Em que caso há outro chamador de um método de conclusão que não conclui o futuro atual?

Questão principal: Se eu quero todo oprintln para ser executado por um diferenteExecutor do que o usado pelo repositório, quais métodos eu preciso para fazer async e fornecer o executor manualmente?

Obviamente othenAccept precisa ser alterado parathenAcceptAsync mas não tenho certeza sobre esse ponto em diante.

Pergunta alternativa: Qual thread conclui o futuro retornado dethenCompose?

Meu palpite é que será o thread que concluirá o futuro retornado do argumento da função. Em outras palavras, eu precisaria também mudarwhenComplete parawhenCompleteAsync.

Talvez eu tenha acabado de complicar as coisas, mas parece que isso pode ficar bem complicado. Preciso prestar muita atenção de onde vêm todos esses futuros. Também do ponto de vista do design, se eu retornar um futuro, como evito que os chamadores usem meu executor? Parece que quebra o encapsulamento. Eu sei que todas as funções de transformação em Scala têm implícitaExecutionContext o que parece resolver todos esses problemas.

questionAnswers(2)

yourAnswerToTheQuestion