Existe uma maneira, mas você não vai gostar. O método a seguir transforma um Future<T>
em CompletableFuture<T>
:
public static <T> CompletableFuture<T> makeCompletableFuture(Future<T> future) {
if (future.isDone())
return transformDoneFuture(future);
return CompletableFuture.supplyAsync(() -> {
try {
if (!future.isDone())
awaitFutureIsDoneInForkJoinPool(future);
return future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
// Normally, this should never happen inside ForkJoinPool
Thread.currentThread().interrupt();
// Add the following statement if the future doesn't have side effects
// future.cancel(true);
throw new RuntimeException(e);
}
});
}
private static <T> CompletableFuture<T> transformDoneFuture(Future<T> future) {
CompletableFuture<T> cf = new CompletableFuture<>();
T result;
try {
result = future.get();
} catch (Throwable ex) {
cf.completeExceptionally(ex);
return cf;
}
cf.complete(result);
return cf;
}
private static void awaitFutureIsDoneInForkJoinPool(Future<?> future)
throws InterruptedException {
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
@Override public boolean block() throws InterruptedException {
try {
future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
return true;
}
@Override public boolean isReleasable() {
return future.isDone();
}
});
}
Obviamente, o problema dessa abordagem é que, para cada Futuro , um fio será bloqueado para aguardar o resultado do Futuro - contradizendo a ideia de futuro. Em alguns casos, pode ser possível fazer melhor. Porém, em geral, não há solução sem esperar ativamente pelo resultado do Futuro .
CompletableFuture.supplyAsync(supplier, new SinglethreadExecutor())
pelo menos não bloquearia os threads comuns do pool.Se a biblioteca que você deseja usar também oferece um método de estilo de retorno de chamada além do estilo Future, você pode fornecer a ela um manipulador que completa o CompletableFuture sem qualquer bloqueio de thread extra. Igual a:
Sem o retorno de chamada, a única outra maneira que vejo para resolver isso é usar um loop de pesquisa que coloca todas as suas
Future.isDone()
verificações em um único encadeamento e, em seguida, chama complete sempre que um Future for gettable.fonte
Se o seu
Future
for o resultado de uma chamada a umExecutorService
método (por exemplosubmit()
), o mais fácil seria usar oCompletableFuture.runAsync(Runnable, Executor)
método.De
para
O
CompletableFuture
é então criado "nativamente".EDIT: Seguindo comentários de @SamMefford corrigidos por @MartinAndersson, se você quiser passar um
Callable
, você precisa chamarsupplyAsync()
, convertendo oCallable<T>
em umSupplier<T>
, por exemplo, com:Como
T Callable.call() throws Exception;
lança uma exceção eT Supplier.get();
não, você precisa capturar a exceção para que os protótipos sejam compatíveis.fonte
CompletableFuture<T> future = CompletableFuture.supplyAsync(myCallable, myExecutor);
supplyAsync
recebe umSupplier
. O código não será compilado se você tentar passar umCallable
.Callable<T>
em aSupplier<T>
.Publiquei um pequeno projeto de futuro que tenta fazer melhor do que o caminho direto na resposta.
A ideia principal é usar o único thread (e, claro, não apenas um loop de rotação) para verificar todos os estados Futures dentro, o que ajuda a evitar o bloqueio de um thread de um pool para cada transformação Future -> CompletableFuture.
Exemplo de uso:
fonte
Sugestão:
http://www.thedevpiece.com/converting-old-java-future-to-completablefuture/
Mas, basicamente:
E, o CompletablePromise:
Exemplo:
fonte
CompletablePromiseContext
não estático e tomaria o parâmetro para o intervalo de verificação (que é definido como 1 ms aqui) e, em seguida, sobrecarregaria oCompletablePromise<V>
construtor para ser capaz de fornecer o seu próprioCompletablePromiseContext
intervalo de verificação possivelmente diferente (mais longo) para longa duraçãoFuture<V>
onde você não não precisa absolutamente ser capaz de executar callback (ou compor) imediatamente após terminar, e você também pode ter uma instância deCompletablePromiseContext
para assistir a um conjunto deFuture
(no caso de você ter muitos)Deixe-me sugerir outra (espero, melhor) opção: https://github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata / concorrente
Resumidamente, a ideia é a seguinte:
CompletableTask<V>
interface - a união doCompletionStage<V>
+RunnableFuture<V>
ExecutorService
para retornarCompletableTask
desubmit(...)
métodos (em vez deFuture<V>
)A implementação usa uma implementação alternativa CompletionStage (preste atenção, CompletionStage em vez de CompletableFuture):
Uso:
fonte