Skip to content

1 Introducción

Introducción

Normalmente, cuando se desarrolla una aplicación concurrente simple en Java se crean varios objetos Runnable y los correspondientes objetos Thread para ejecutarlos. Si nuestro programa debe ejecutar muchas tareas concurrentes, este método tiene varias desventajas:

  • Se debe implementar toda la información relacionada con el código para la gestión de los objetos Thread (creación, terminación, obtención de resultados, etc.).
  • Se debe crear un objeto Thread por cada tarea. Si se debe ejecutar un gran número de tareas, este hecho puede afectar al rendimiento de la aplicación.
  • Se debe controlar y gestionar eficientemente los recursos del ordenador. Si se crean demasiados hilos, se puede saturar el sistema.

Desde Java 5, la API de concurrencia de Java proporciona un mecanismo para resolver estos problemas, llamado Executor framework (entorno de trabajo de ejecución), que se construye en base a la interfaz Executor (ejecutor), su subinterfaz ExecutorService (servicio de ejecución) y la clase ThreadPoolExecutor (ejecutor mediante grupos de hilos), que implementa ambas interfaces.

Este mecanismo separa por un lado la creación de tareas y por otro lado su ejecución, aplicando el patrón de diseño conocido como command. Tan sólo será necesario implementar los objetos Runnable correspondientes a las tareas y enviárselos al ejecutor, quien será responsable de su ejecución. Para ello el ejecutor gestiona un grupo de hilos (threadpool) en el que va ejecutando las tareas que se le van enviando. Dependiendo del tipo de ejecutor del que se trate, en algunos casos es posible aumentar o decrementar el número de hilos del threadpool atendiendo a las necesidades.

El objetivo del empleo de un threadpool de work thread es la posibilidad de reutilizar hilos secundarios para ejecutar varias tareas, minimizando así el tiempo necesario para crear hilos. Así cada hilo del threadpool ejecuta un bucle en el que cada iteración trata de obtener (take) la siguiente tarea de una cola de tareas BlockingQueue del ejecutor (workQueue), en la se van insertando (offer) conforme son enviadas (submit). Si no existe ninguna tarea en la cola el hilo quedará bloqueado esperando (normalmente un determinado tiempo máximo). Una vez obtenido la tarea la ejecuta (run). Si transcurrido el tiempo máximo de espera el hilo no tiene tarea que ejecutar, dependiendo del tipo de ejecutor, puede que el hilo sea directamente finalizado, reduciendo el número de hilos del threadpool del ejecutor.

ThreadPoolExecutor

Figura 1 - ThreadPoolExecutor