I've read that CompletableFuture
has the ability to merge multiple futures with the runAfterBoth
but what if I want to merge more than two?
CompletableFuture<Boolean> a = new CompletableFuture<>();
CompletableFuture<Boolean> b = new CompletableFuture<>();
CompletableFuture<Boolean> c = new CompletableFuture<>();
List<CompletableFuture<Boolean>> list = new LinkedList<>();
list.add(a);
list.add(b);
list.add(c);
// Could be any number
for (CompletableFuture<Boolean> f : list) {
f.runAfter..
}
My use case is that I'm sending messages out to multiple sockets to locate a single object which may or may not be on any one of them.
I'm currently looking at this as a solution:
CompletableFuture<Boolean> a = new CompletableFuture<>();
CompletableFuture<Boolean> b = new CompletableFuture<>();
CompletableFuture<Boolean> c = new CompletableFuture<>();
List<CompletableFuture<Boolean>> list = new LinkedList<>();
list.add(a);
list.add(b);
list.add(c);
CompletableFuture<Boolean> result = new CompletableFuture<>();
Thread accept = new Thread(() -> {
for (CompletableFuture<Boolean> f : list)
if (f.join() != null)
result.complete(f.join());
});
accept.start();
// Actual boolean value returned
result.get();
But it's kind of a mess. And in my case, I want to continue processing as soon as I get a valid result (not null) instead of waiting on the invalid results as well.
For example, a
takes 5 seconds and the loop is waiting on it even though b
has already completed in 2 seconds; but the loop doesn't know that because it's still waiting on a
.
Is there a pattern to work with joining multiple asynchronous futures where I can respond immediately on a successful completion?
Another possibility:
public static class FutureUtil {
public static <T> CompletableFuture<T> anyOfNot(
Collection<CompletableFuture<T>> collection,
T value,
T defaultValue)
{
CompletableFuture<T> result = new CompletableFuture<>();
new Thread(() -> {
for (CompletableFuture<T> f : collection) {
f.thenAccept((
T r) -> {
if ((r != null && !r.equals(value))
|| (value != null && !value.equals(r)))
result.complete(r);
});
}
try {
for (CompletableFuture<T> f : collection)
f.get();
}
catch (Exception ex) {
result.completeExceptionally(ex);
}
result.complete(defaultValue);
}).start();
return result;
}
}
Example use:
CompletableFuture<Boolean> a = new CompletableFuture<>();
CompletableFuture<Boolean> b = new CompletableFuture<>();
CompletableFuture<Boolean> c = new CompletableFuture<>();
List<CompletableFuture<Boolean>> list = new LinkedList<>();
list.add(a);
list.add(b);
list.add(c);
CompletableFuture<Boolean> result = FutureUtil.anyOfNot(list, null, false);
result.get();