Java ExecutorService es la interfaz que nos permite ejecutar tareas en subprocesos de forma asincrónica. La interfaz Java ExecutorService está presente en el paquete java.util.concurrent. ExecutorService ayuda a mantener un grupo de subprocesos y les asigna tareas. También proporciona la posibilidad de poner en cola tareas hasta que haya un hilo libre disponible si la cantidad de tareas es mayor que los hilos disponibles.
Métodos de Java ExecutorService
Método | Descripción |
---|---|
booleano awaitTermination (tiempo de espera prolongado, unidad TimeUnit) | Este método bloquea la tarea para ingresar a ExecutorService hasta que todas las tareas se hayan completado después de la solicitud de cierre, o se agote el tiempo de espera determinado, o se interrumpa el subproceso actual, lo que ocurra primero. |
Lista | Este método ejecuta la lista de tareas proporcionadas y devuelve la lista de Futuros que contienen los resultados de todas las tareas cuando se completan. |
Lista | Este método ejecuta la lista de tareas proporcionadas y devuelve la lista de Futuros que contienen los resultados de todas las tareas cuando se completan o expira el tiempo de espera, lo que ocurra primero. |
T invocarAny(Colección extends Callable>tareas) | Este método ejecuta la lista de tareas proporcionadas y devuelve el resultado de una tarea que se completa sin generar ninguna excepción. |
T invocarAny(Colección extends Callable>tareas, tiempo de espera prolongado, unidad TimeUnit) | Este método ejecuta la lista de tareas proporcionadas y devuelve el resultado de una tarea que se completa sin generar ninguna excepción antes de que transcurra el tiempo de espera. |
booleano esShutdown() | Este método devuelve si el ejecutor dado está cerrado o no. |
booleano está terminado() | Este método devuelve verdadero si todas las tareas se han ejecutado después del apagado. |
cierre nulo() | Este método permite completar tareas enviadas previamente al ExecutorService y no permite aceptar ninguna otra tarea. |
Lista de apagadoAhora() | Este método detiene todas las tareas que se ejecutan activamente, detiene la ejecución de las tareas en cola y devuelve la lista de tareas que están en cola. |
Envío futuro (tarea invocable) | Este método envía una tarea que devuelve valor para su ejecución y devuelve el Futuro, que representa el resultado pendiente de la tarea. |
Envío futuro (tarea ejecutable) | Este método envía una tarea para su ejecución y devuelve un futuro que representa esa tarea. Devuelve nulo al finalizar con éxito. |
Envío futuro (tarea ejecutable, resultado T) | Este método envía una tarea para su ejecución y devuelve un futuro que representa esa tarea. |
Un programa simple de Java ExecutorService
public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(10); executorService.execute(new Runnable() { @Override public void run() { System.out.println('ExecutorService'); } }); executorService.shutdown(); } }
Producción:
En este programa, creamos un ExecutorService con diez subprocesos y le asignamos una implementación ejecutable anónima que realiza una tarea para imprimir 'ExecutorService' y, una vez finalizada su tarea, cerramos el servicio ejecutor.
Cómo utilizar el servicio ejecutor de Java
Creación de instancias de ExecutorService
Podemos utilizar Java ExecutorService para crear un único subproceso, un grupo de subprocesos o un grupo de subprocesos programado. La clase Executors proporciona métodos de fábrica para crear una instancia de un ExecutorService de la siguiente manera:
ExecutorService executorService1 = Executors.newSingleThreadExecutor(); //Creates //a ExecutorService object having a single thread. ExecutorService executorService2 = Executors.newFixedThreadPool(10); // Creates a //ExecutorService object having a pool of 10 threads. ExecutorService executorService3 = Executors.newScheduledThreadPool(10); //Creates a scheduled thread pool executor with 10 threads. In scheduled thread //pool, we can schedule tasks of the threads.
Asignar tareas a ExecutorServices
Para asignar una tarea a ExecutorService, podemos utilizar los siguientes métodos:
- ejecutar (tarea ejecutable)
- enviar (tarea ejecutable) / enviar (tarea invocable)
- invocarAny(Colección extends Callable>tareas)
- invocarTodo(Colección extends Callable>tareas)
Ejemplo de asignación de una tarea a ExecutorService usando el método ejecutar()
El método ejecutar() de Java ExecutorService toma un objeto ejecutable y realiza su tarea de forma asincrónica. Después de realizar la llamada al método de ejecución, llamamos al método de apagado, que bloquea cualquier otra tarea para ponerla en cola en el servicio ejecutor.
public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.execute(new Runnable() { @Override public void run() { System.out.println('ExecutorService'); } }); executorService.shutdown(); } }
Producción:
ExecutorService
Ejemplo de asignación de una tarea a ExecutorService usando submit()
El método submit() toma un objeto ejecutable y devuelve un objeto Future. Este objeto se utiliza posteriormente para comprobar el estado de Runnable, ya sea que haya completado la ejecución o no.
public class ExecutorServiceExample { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(new Runnable() { @Override public void run() { System.out.println('ExecutorService'); } }); } }
Ejemplo de asignación de una tarea a ExecutorService usando el método invokeAny()
El método invokeAny() toma una colección de objetos Callablle u objetos de clases que implementan Callable. Este método devuelve el objeto futuro del objeto invocable que se ejecuta con éxito primero.
public class ExecutorServiceExample { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<callable> callables = new HashSet<callable>(); callables.add(new Callable() { public String call() throws Exception { return 'Task 1'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 2'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 3'; } }); String result = executorService.invokeAny(callables); System.out.println('result = ' + result); executorService.shutdown(); } } </callable></callable>
Producción:
result = Task 1
El resultado almacena la Tarea 1 ya que el primer objeto invocable se ejecuta con éxito primero.
Ejemplo de asignación de una tarea a ExecutorService usando el método invokeAll()
El método invokeAll() toma una colección de objetos invocables que tienen tareas y devuelve una lista de objetos futuros que contienen el resultado de todas las tareas.
public class ExecutorServiceExample { public static void main(String[] args) throws InterruptedException, ExecutionException { ExecutorService executorService = Executors.newSingleThreadExecutor(); Set<callable> callables = new HashSet<callable>(); callables.add(new Callable() { public String call() throws Exception { return 'Task 1'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 2'; } }); callables.add(new Callable() { public String call() throws Exception { return 'Task 3'; } }); java.util.List<future> futures = executorService.invokeAll(callables); for(Future future : futures){ System.out.println('future.get = ' + future.get()); } executorService.shutdown(); } } </future></callable></callable>
Producción:
future.get = Task 1 future.get = Task 3 future.get = Task 2
Cómo cerrar ExecutorService
Una vez que hayamos terminado con las tareas asignadas a ExecutorService, tenemos que cerrarlo porque ExecutorService realiza la tarea en diferentes subprocesos. Si no cerramos ExecutorService, los subprocesos seguirán ejecutándose y la JVM no se cerrará.
El proceso de apagado se puede realizar mediante los siguientes tres métodos:
- método de apagado()
- método apagadoAhora()
- método awaitTermination()