Como ingeniero de back-end, nos enfrentamos a situaciones para procesar los datos de forma asíncrona. Hoy veamos cómo se hace en Java y varias formas de hacerlo.

Thread

El componente muy básico pero tan poderoso de la concurrencia de Java es Thread. El Hilo de Java en realidad está asociado con el Hilo del Sistema Operativo. La forma muy básica de crear un Thread es extendiéndolo y anulando el run :

Comenzar el hilo hace que el run() ser llamado.
Tu puedes preguntar; sí, Thread tiene toneladas de otros métodos que se pueden anular:

  • En la mayoría de los casos, no queremos anular otros métodos del hilo.
  • Una vez que extendemos el Thread clase, la clase de extensión pierde su capacidad de extenderse más, ya que Java no admite herencias múltiples.
  • Cada subproceso tiene su propio objeto cuando lo ampliamos, y no es bueno para la salud de la memoria cuando hay toneladas de Objects of the extended Thread creado.

Java soluciona estos problemas con la interfaz Runnable. En realidad, Thread tiene un método sobrecargado que toma Runnable.

Runnable

Runnable es una interfaz que tiene un solo método: run(). Sí, Runnable es una interfaz funcional y su instancia se puede crear con la función lambda. Sin embargo, es una manera fácil de hacer esto; para cosas complejas, nos gustaría implementarlo. Vea la diferencia aquí. Se trata del requisito:

Aunque Runnable tiene un run(), no es un subproceso sino solo una clase de Java hasta que (pasado a) Thread toma el control. El inicio del subproceso hace que el objeto ejecutable run() ser llamado.

Sí, Java lo resolvió en la versión 1.5 y es Callable.

Callable<V>

Callable es una interfaz genérica. ¿Por qué? Ejecute este comando del valor de retorno como el genérico ejecute este comando. Callable es también una interfaz funcional y call() es el único método, un método sin argumentos que arroja una excepción y devuelve el valor genérico de ejecución de este comando.

La implementación de Callable es muy similar a Runnable:

Vea aquí, la llamada procesa los datos y devuelve un valor que se puede recopilar después de la ejecución. Pero, ¿hay una gran diferencia en invocarlo? Usamos ExecutorService para invocar y Future para sostener el resultado. Hablemos de por qué.

Como puede ver, no hay un comportamiento controlado de creación y ejecución de subprocesos (ejecutables o invocables también). Es posible que deseemos controlar la cantidad de subprocesos que se ejecutan a la vez, ya que cada uno de ellos está asociado con los subprocesos del sistema operativo. La cantidad de subprocesos que ejecutamos debe ser menor que la cantidad de núcleos de CPU disponibles. Todos juntos, Java lo resuelve por ExecutorService interfaz.
Arriba hay un artículo informativo sobre Programación asíncrona en Java: Parte I.
No dude en contactarnos a través de la sección de comentarios, en caso de que tenga alguna pregunta sobre las instrucciones que compartimos anteriormente.