#java-8 #completable-future
#java-8 #завершаемое будущее
Вопрос:
Как улучшить функцию ниже, где getB, getC, getD имеют зависимость от A и должны ждать завершения перед вызовом. Однако я хочу вызвать B C D одновременно после завершения.
Спасибо за всю помощь
примечание: все dbService возвращают завершаемое будущее
CompletableFuture<List<A>> a= dbService.getA(request);
a.thenApply(a-> {
try {
return dbService.getB(a);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
})
.thenAccept (result->{
//do something with B
});
a.thenApply(a-> {
try {
return dbService.getC(a);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
})
.thenAccept (result->{
//do something with C
});
a.thenApply(a-> {
try {
return dbService.getD(a);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
})
.thenAccept (result->{
//do something with D
});
Комментарии:
1. Использовать
thenApplyAsync
?2. Вы имеете в виду объединение всего с applyAsync ? если да, то как я могу повторно ввести параметры A
3. Что вы имеете в виду? Просто замените все три
thenApply
наthenApplyAsync
.4. я имею в виду, есть ли возможность объединить все три в одной функции? Спасибо
5. Вы сказали, что хотите, чтобы B, C и D выполнялись одновременно. Так что нет, у вас не может быть этого и этих одновременных вызовов в одной функции. В этом тоже нет смысла. Если вы хотите упростить код, исправьте метод dbService так, чтобы он не выдавал
InterruptedException
, так как это противоречит возвращению объекта, представляющего асинхронную операцию, но объявляет выдачу исключения, указывающего на операцию ожидания.
Ответ №1:
Если вас не волнует возврат B, C, D, то:
CompletionStage<List<A>> aFuture = dbService.getA(request);
aFuture.whenCompleteAsync((a, ex) -> {
if (ex != null) {
dbService.getB(a);
// ...
} else {
// ...
}
});
aFuture.whenCompleteAsync((a, ex) -> {
if (ex != null) {
dbService.getC(a);
// ...
} else {
// ...
}
});
aFuture.whenCompleteAsync((a, ex) -> {
if (ex != null) {
dbService.getD(a);
// ...
} else {
// ...
}
});
Ваша программа вернется к основному циклу событий, как только dbService.getA(request)
начнется, т. е. еще до его завершения. И когда это завершается, каждый из 3 блоков выполняется (из-за того, что они были поставлены в очередь whenComplete
) в разных потоках (отличных от основного и друг от друга, из-за Async
).
Если вы действительно хотите что-то сделать с возвратами B, C и D, то:
CompletionStage<List<A>> aFuture = dbService.getA(request);
CompletionStage<B> bFuture = aFuture.thenApplyAsync(a -> {
return dbService.getB(a);
});
CompletionStage<C> cFuture = aFuture.thenApplyAsync(a -> {
return dbService.getC(a);
});
CompletionStage<D> dFuture = aFuture.thenApplyAsync(a -> {
return dbService.getD(a);
});
CompletionStage<Something> sFuture = bFuture.thenCompose(b -> {
cFuture.thenCompose(c -> {
dFuture.thenApply(d -> {
// do something with b, c, d
return new Something();
});
});
});
Вы можете сократить это с помощью thenCombine
, который похож на thenApply
, который ожидает 2 фьючерса:
CompletionStage<List<A>> aFuture = dbService.getA(request);
CompletionStage<B> bFuture = aFuture.thenApplyAsync(a -> {
return dbService.getB(a);
});
CompletionStage<C> cFuture = aFuture.thenApplyAsync(a -> {
return dbService.getC(a);
});
CompletionStage<D> dFuture = aFuture.thenApplyAsync(a -> {
return dbService.getD(a);
});
CompletionStage<Something> sFuture = bFuture.thenCompose(b -> {
cFuture.thenCombine(dFuture, (c, d) -> {
// do something with b, c, d
return new Something();
});
});
Чтобы распространить это на любое количество одновременных этапов, мне нравится использовать пакет CompletableFutures от Spotify следующим образом:
CompletionStage<List<A>> aFuture = dbService.getA(request);
CompletionStage<B> bFuture = aFuture.thenApplyAsync(a -> {
return dbService.getB(a);
});
CompletionStage<C> cFuture = aFuture.thenApplyAsync(a -> {
return dbService.getC(a);
});
CompletionStage<D> dFuture = aFuture.thenApplyAsync(a -> {
return dbService.getD(a);
});
CompletionStage<Something> sFuture = CompletableFutures.combine((bFuture, cFuture, dFuture) -> {
// do something with b, c, d
return new Something();
}