我已经读过CompletableFuture
能够将多个期货与runAfterBoth
合并,但如果我想合并多于两个呢?
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..
}
我的用例是我将消息发送到多个套接字以查找单个对象,这些对象可能在也可能不在其中任何一个上。
我目前正在将此视为一种解决方案:
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();
但这有点乱。在我的情况下,我想在得到有效结果(非空)后继续处理,而不是等待无效结果。
例如,a
需要5秒钟,即使b
已在2秒内完成,循环也在等待它;但循环不知道,因为它仍在等待a
。
是否有一种模式可以加入多个异步期货,我可以在成功完成后立即回应?
另一种可能性:
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;
}
}
使用示例:
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();
答案 0 :(得分:1)
如果您知道如果列表中的CF将使用非空值完成至少一个,您可以尝试:
public static <T> CompletableFuture<T> firstNonNull(List<CompletableFuture<T>> completableFutures) {
final CompletableFuture<T> completableFutureResult = new CompletableFuture<>();
completableFutures.forEach(cf -> cf.thenAccept(v -> {
if (v != null) {
completableFutureResult.complete(v);
}
}));
return completableFutureResult;
}
如果无法保证至少有一个CF会返回非空值,则需要更复杂的内容:
public static <T> CompletableFuture<T> firstNonNull(List<CompletableFuture<T>> completableFutures, T defaultValue) {
final CompletableFuture<T> completableFutureResult = new CompletableFuture<>();
completableFutures.forEach(cf -> cf.thenAccept(v -> {
if (v != null) {
completableFutureResult.complete(v);
}
}));
//handling the situation where all the CFs returned null
CompletableFuture<Void> allCompleted = CompletableFuture
.allOf((CompletableFuture<?>[]) completableFutures.toArray());
allCompleted.thenRun(() -> {
//checking first if any of the completed delivered a non-null value, to avoid race conditions with the block above
completableFutures.forEach(cf -> {
final T result = cf.join();
if (result != null) {
completableFutureResult.complete(result);
}
});
//if still not completed, completing with default value
if ( !completableFutureResult.isDone()) {
completableFutureResult.complete(defaultValue);
}
});
return completableFutureResult;
}