3 Métodos factoría para construir CompletableFutures¶
Introducción¶
La clase CompletableFuture
incorpora una serie de métodos estáticos factoría para la creación de objetos CompletableFuture
que ejecutan tareas de forma asíncrona.
Para ejecutar un Runnable¶
La manera más sencilla de crear una tarea asíncrona que haga uso de CompletableFuture
es usar el método estático CompletableFuture.runAsync(runnable)
. Este método recibe el código a ejecutar asíncronamente en forma de objeto Runnable
y retorna un CompletableFuture<Void>
, ya que un Runnable
no retorna nada. Por ejemplo:
private void runAsyncExample() {
CompletableFuture.runAsync(this::printInfo);
System.out.printf("%s - Main\n", Thread.currentThread().getName());
}
private void printInfo() {
System.out.printf("%s - Runnable\n", Thread.currentThread().getName());
}
La tarea asíncrona será ejecutada en un hilo del ForkJoinPool.commonPool()
.
El método está sobrecargado runAsync(runnable, executor)
de manera que podemos pasarle un segundo parámetro con el ejecutor que debe usarse para ejecutar la tarea secundaria. Por ejemplo:
private void runAsyncExecutorExample() {
CompletableFuture.runAsync(this::printInfo, Executors.newCachedThreadPool());
System.out.printf("%s - Main\n", Thread.currentThread().getName());
}
private void printInfo() {
System.out.printf("%s - Runnable\n", Thread.currentThread().getName());
}
En este ejemplo usamos la sintaxis de referencia a método a la de especificar el Runnable
.
Dado que el método run()
del objeto Runnable
no retorna nada, runAsync()
retorna un CompletableFuture<Void>
, que NO podremos encadenar con ninguna otra operación, por lo que su utilidad no va más allá de ejecutar una tarea de forma asíncrona sin que ésta retorne ningún valor.
Para ejecutar un Supplier¶
Sin embargo, lo habitual es que la tarea que queremos que se ejecute de forma asíncrona retorna algún valor, por lo que la clase CompletableFuture
proporciona el método estático supplyAsync(supplier)
, que en vez de recibir un Runnable
, recibe un Supplier
. Este método retorna un CompletableFuture<T>
, donde T
el el tipo de retorno de la función del Supplier
. Por ejemplo:
private void supplyAsyncExample() {
CompletableFuture<Integer> cf = CompletableFuture.supplyAsync(this::generateNumber);
try {
Integer value = cf.get();
printNumber(value);
} catch (InterruptedException ignored) {
} catch (ExecutionException e) {
System.out.println("Exception thrown getting value from supplier");
}
}
private int generateNumber() {
System.out.printf("%s - Supplier\n", Thread.currentThread().getName());
return 2;
}
private void printNumber(Integer value) {
System.out.printf("%s - %d\n",
Thread.currentThread().getName(), value);
}
La tarea asíncrona será ejecutada en un hilo del ForkJoinPool.commonPool()
.
El método está sobrecargado, supplyAsync(supplier, executor)
, de manera que podemos pasarle un segundo parámetro con el objeto Executor
que debe usarse para ejecutar la tarea secundaria.