Skip to content

1 Introducción a CompletableFuture

Introducción

La interfaz Future fue incorporada en Java 5 para representar el resultado de operaciones asíncronas, para indicar que dicho resultado estaría disponible en el futuro. Sin embargo, dicha interfaz no incluía ningún método que permitiera combinar estas operaciones de manera asíncrona o de gestionar los posibles errores. Así, si debíamos encadenar dos tareas asíncronas, debíamos bloquearnos hasta que terminara de ejecutarse la primera, normalmente llamando al método get() del objeto Future retornado por la tarea, para posteriormente lanzar la segunda tarea pasándole el resultado obtenido por la primera para que se ejecutara de manera asíncrona. Como vemos, en realidad no podíamos desentendernos de la ejecución de la cadena de tareas, ya que éramos nosotros los que debíamos de encadenar la finalización de la ejecución de la primera tarea con el inicio de la ejecución de la segunda.

Con el objetivo de mejorar la funcionalidad aportada por la interfaz Future, la API de concurrencia de Java 8 incluyó la clase CompletableFuture<T>. Esta clase implementa la interfaz Future<T>, por lo que podemos usar un objeto de CompletableFuture<T> dentro de nuestra tarea para retornar en algún momento futuro un resultado de la clase T, de igual manera a cómo hacíamos con Future<T>, pero además CompletableFuture<T> implementa la interfaz CompletionStage<T>, y es esta interfaz, la que le proporciona la funcionalidad necesaria para encadenar la ejecución asíncrona de otras tareas cuando la ejecución de nuestra tarea haya finalizado y se haya obtenido el resultado.

Debemos tener en cuenta que la clase CompletableFuture proporciona muchísimos métodos, más de 60, por lo que más que una clase es todo un framework, que proporciona un modelo de programación concurrente asíncrona. Sus principales características son:

  • Permite el disparo automático y asíncrono de operaciones dependientes de otras cuando éstas últimas son completadas.
  • Las operaciones asíncronas pueden ser ejecutadas concurrentemente en thread pools, permitiéndonos usar por defecto un fork-join pool común, o especificar explícitamente el thead pool a usar.
  • Puede combinarse con los streams de Java 8.
  • Al usar el framework de CompletableFuture habitualmente no es necesario desarrollar ningún mecanismo de sincronización entre los hilos. En aquellos casos donde es necesaria la sincronización podemos usar las estructuras de datos thread-safe disponibles en Java.
  • Mejora las características la interfaz Future, ya que permite completar explícitamente un CompletableFuture, algo que no era posible hacer en un Future.
  • Se pueden encadenar operaciones usando una sintaxis fluida, para manejar operaciones asíncronas de forma eficiente y clara.