I have a method for some repository class that returns CompletableFuture . The code that terminates these futures uses a third-party library that blocks. I intend to have a separate limited Executor that this repository class will use to make these blocking calls.
Here is an example:
public class PersonRepository { private Executor executor = ... public CompletableFuture<Void> create(Person person) {...} public CompletableFuture<Boolean> delete(Person person) {...} }
The rest of my application will compose these futures and do some other things with the results. When these other functions are supplied in thenAccept , thenCompose , whenComplete , etc., I do not want them to be run in Executor for the repository.
Another example:
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(); }); }
The JavaDoc says:
The actions provided for dependent terminations of non-asynchronous methods can be performed by a thread that completes the current CompletableFuture or by any other caller of the termination method.
Side question: Why is there or here? In which case is there another calling completion method that does not complete the current future?
The main question: If I want all println executed by a different Executor than the other used by the repository, what methods do I need to make async and provide to the executor manually?
Obviously, thenAccept needs to be changed to thenAcceptAsync , but I'm not sure about that.
Alternative question: Which thread completes the returned future from thenCompose ?
I assume that this will be any thread that completes the future returned from the function argument. In other words, I will also need to change whenComplete to whenCompleteAsync .
I may be complicating things too much, but it seems like it can get quite complicated. I need to pay a lot of attention to where all these futures come from. Also in terms of design, if I get my future right back, how can I prevent callers from using my artist? It looks like it destroys encapsulation. I know that all conversion functions in Scala accept an implicit ExecutionContext , which seems to solve all these problems.