programación - platzi java
Transforme el futuro de Java en un futuro completable (4)
Java 8 presenta CompletableFuture
, una nueva implementación de Future que se puede componer (incluye un grupo de métodos thenXxx). Me gustaría utilizar esto de manera exclusiva, pero muchas de las bibliotecas que deseo utilizar solo devuelven instancias Future
no compibles.
¿Hay alguna manera de concluir las instancias Future
devueltas dentro de un CompleteableFuture
para que pueda componerlo?
Hay una manera, pero no te gustará. El siguiente método transforma un Future<T>
en un CompletableFuture<T>
:
public static <T> CompletableFuture<T> makeCompletableFuture(Future<T> future) {
return CompletableFuture.supplyAsync(() -> {
try {
return future.get();
} catch (InterruptedException|ExecutionException e) {
throw new RuntimeException(e);
}
});
}
Obviamente, el problema con este enfoque es que, para cada futuro , un hilo se bloqueará para esperar el resultado del futuro, lo que contradice la idea de futuro. En algunos casos, podría ser posible hacerlo mejor. Sin embargo, en general, no hay solución sin esperar activamente el resultado del futuro .
Permítanme sugerir otra opción (con suerte, mejor): https://github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata /concurrente
En resumen, la idea es la siguiente:
- Introduzca la interfaz
CompletableTask<V>
: la unión deCompletionStage<V>
+RunnableFuture<V>
- Warp
ExecutorService
para devolverCompletableTask
de los métodos desubmit(...)
(en lugar deFuture<V>
) - Hecho, tenemos futuros convertibles Y compostables.
La implementación utiliza una implementación alternativa de CompletionStage (preste atención, CompletionStage en lugar de CompletableFuture):
Uso:
J8ExecutorService exec = J8Executors.newCachedThreadPool();
CompletionStage<String> = exec
.submit( someCallableA )
.thenCombineAsync( exec.submit(someCallableB), (a, b) -> a + " " + b)
.thenCombine( exec.submit(someCallableC), (ab, b) -> ab + " " + c);
Si la biblioteca que desea utilizar también ofrece un método de estilo de devolución de llamada además del estilo Futuro, puede proporcionarle un controlador que complete el CompletableFuture sin ningún bloqueo adicional de subprocesos. Al igual que:
AsynchronousFileChannel open = AsynchronousFileChannel.open(Paths.get("/some/file"));
// ...
CompletableFuture<ByteBuffer> completableFuture = new CompletableFuture<ByteBuffer>();
open.read(buffer, position, null, new CompletionHandler<Integer, Void>() {
@Override
public void completed(Integer result, Void attachment) {
completableFuture.complete(buffer);
}
@Override
public void failed(Throwable exc, Void attachment) {
completableFuture.completeExceptionally(exc);
}
});
completableFuture.thenApply(...)
Sin la devolución de llamada, la única otra forma en que veo resolver esto es usar un ciclo de sondeo que coloca todas las comprobaciones de Future.isDone()
en un solo hilo y luego invocando completar cada vez que se puede obtener un futuro.
Publiqué un pequeño proyecto de futuro que trata de hacer una mejor manera que la respuesta directa .
La idea principal es utilizar el único hilo (y, por supuesto, no solo un ciclo de giro) para verificar todos los estados futuros en el interior, lo que ayuda a evitar el bloqueo de un hilo de un grupo para cada transformación Future -> CompletableFuture.
Ejemplo de uso:
Future oldFuture = ...;
CompletableFuture profit = Futurity.shift(oldFuture);