I need to call a method with different input parameters (like id) asynchronously, the method returns true or false, and the false output is not desirable, so I should wait for a true output. As soon as I get a true one, I do not care about the other calls, just I need to know the true output is corresponding with which input (id).
I call this piece of code, how should I know the input id of responded method? It might have a more completableFuture. The next question is in case of getting false, how can I skip and wait for getting true, because I need to recieve true from one of the myService.myMethod(int input)?
CompletableFuture<Boolean> completableFuture= CompletableFuture.supplyAsync(() -> myService.myMethod(1));
CompletableFuture<Boolean> completableFuture2= CompletableFuture.supplyAsync(() -> myService.myMethod(2));
CompletableFuture<Boolean> completableFuture3= CompletableFuture.supplyAsync(() -> myService.myMethod(3));
CompletableFuture<Boolean> completableFuture4= CompletableFuture.supplyAsync(() -> myService.myMethod(4));
CompletableFuture<Object> result =
CompletableFuture.anyOf(completableFuture, completableFuture2,completableFuture3,,completableFuture4).thenApply(s -> s);
CodePudding user response:
The fact that each result can be false makes this a bit tricky, because you can't abort too early. The following should work; it lets each CompletableFuture
publish its results to a queue, as well as a sentinel value that indicates that all work is done. You then take the first element from the queue that was successful; if there is none, you know that all results are false if you read the sentinel value.
record Result (int id, boolean value) {}
final Result sentinel = new Result(Integer.MIN_VALUE, false);
// one more than the number of results, for the sentinel
BlockingDeque<Result> results = new LinkedBlockingDeque<>(5);
// the number of results exactly
CountDownLatch latch = new CountDownLatch(4);
CompletableFuture.runAsync(() -> {
Record record = new Record(1, myService.myMethod(1));
results.add(record);
latch.countDown();
});
// etc for 2-4
CompletableFuture.runAsync(() -> {
try {
latch.await();
} catch (InterruptedException e) {
// log or something?
} finally {
results.add(sentinel);
}
});
Result result = results.take();
while (!result.value() && !result.equals(sentinel)) {
result = results.take();
}
The sentinel is only added once each result has been published (due to the CountDownLatch
), ensuring it's always the last element.
When the loop ends, if result.equals(sentinel)
, all results were false. Otherwise, result
contains the id for the first available successful result.