Ir al contenido principal

Paralelismo en JAVA Executors (ExecutorService, Callables y Futures).


Código fuente articulo:
https://www.dropbox.com/s/jci67120hmd0uce/Paralelismo.zip?dl=0

Para manejo de concurrencia Java desde la versión 5 presento el Concurrency API  este presento una mejora substancial en el manejo de hilos y procesos en paralelo, antes solo contabas con Thread y Runnable. lo que te obligaba a controlar la creación y el numero de hilos de ejecución, no te entregaba un resultado del procesamiento y no te dejaba controlar las Excepciones que lanzara un hilo...un hilo se lanzaba y amenos que le enviaras un un CallBack perdías todo contacto con el.
Para solucionar este problema se crearon dos tipos de objetos Callables y Futures. estos dos te permiten encapsular una tarea asignándole un tipo de Objeto que sera el valor de retorno y hacer seguimiento a las tareas que ejecuto en paralelo pudiendo preguntar si ya termino, que resultado lanzo y que excepciones ocurrieron.

Arranquemos con la implementación de Callable, Callable es una interfaz que te permite definir que
clase regresara la ejecución de una tarea y se ve así;

public abstract interface java.util.concurrent.Callable<T>{ ....

cuando la implementes quedara así

public class CallableDuerme implements Callable<String> {

Implementar esta interfaz de obliga a implementar el metodo call(), este metodo sera el que llamara el Executor para completar la tarea.

@Override
 public String call() throws Exception {....

si te fijas la implementación por defecto añade un Exception , si recuerdas de POO cuando
implementes el metodo puedes no incluir ninguna Exception

@Override
 public String call() {....

O ser mas especifico en la Exception que voy a manejar, es decir cualquier Exception  que herede de
Exception  como IOException o InterruptedException

@Override
 public String call() throws InterruptedException {

En nuestro ejemplo vamos a utilizar InterruptedException  porque vamos a dormir las tareas un rato mientras se ejecutan.

entonces nuestra implementacion de Callable, va a ser una clase que tenga una propiedad nombre para saber que tarea fue la que se termino y que va a dormir un tiempo entre 0 y 20 segundos para simular que esta haciendo algo. y se vera así:

public class CallableDuerme implements Callable<String> {

 private String nombre;

 public CallableDuerme(String nombre) {

  this.nombre = nombre;
 }
 @Override
 public String call() throws InterruptedException {

  Random ran= new Random();
  TimeUnit.SECONDS.sleep(ran.nextInt(20));
  return "Termine de dormir soy:"+nombre;
 }
}

Ya tenemos la tarea ahora definiremos el objeto que se encargara de ejecutar nuestra tareas en n cantidad de hilos así:

ExecutorService executor = Executors.newFixedThreadPool(2);

crearemos un arreglo de Futures donde guardaremos la referencia a nuestras tareas para poder recuperar el resultado de su ejecución.

List<Future<String>> future= new ArrayList<>();

después crearemos tres tareas que enviaremos a ejecutar en nuestro executor y que reverenciaremos
con un futuro y guardaremos las referencias en una lista.

future.add(executor.submit(new CallableDuerme("Juanita")));
  future.add(executor.submit(new CallableDuerme("Marrrrria")));
  future.add(executor.submit(new CallableDuerme("Daniela")));

ahora nos quedaremos monitoreando nuestras tareas hasta que todas terminen:

int listos=0;

  while(listos<3){
   listos=0;
   for(Future<String> resultado:future){
 
    if(resultado.isDone()){
     listos++;
     try {
      System.out.println(resultado.get());
     } catch (InterruptedException | ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
    System.out.println(listos);
 
   }
  }

Al final nuestra clase se vera así

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;

public class CallableDuerme implements Callable<String> {

 private String nombre;

 public CallableDuerme(String nombre) {

  this.nombre = nombre;
 }
 @Override
 public String call() throws InterruptedException {

  Random ran= new Random();
  TimeUnit.SECONDS.sleep(ran.nextInt(20));
  return "Termine de dormir soy:"+nombre;
 }
 public static void main(String[] args) {

  ExecutorService executor = Executors.newFixedThreadPool(2);
  List<Future<String>> future= new ArrayList<>();

  future.add(executor.submit(new CallableDuerme("Juanita")));
  future.add(executor.submit(new CallableDuerme("Marrrrria")));
  future.add(executor.submit(new CallableDuerme("Daniela")));

  int listos=0;

  while(listos<3){
   listos=0;
   for(Future<String> resultado:future){
 
    if(resultado.isDone()){
     listos++;
     try {
      System.out.println(resultado.get());
     } catch (InterruptedException | ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
     }
    }
    System.out.println(listos);
 
   }
  }

 
 }

}

Ahora ya tienes lo básico de Executors, sabes que es un Callable y tienes las herramientas para recuperar el resultado de la ejecución de las tareas con los Futures. ya lo sabes todo, ahora sal a buscarte la vida y no te andes quejando.

Comentarios

Entradas populares de este blog

Conectarse al LDAP (directorio activo) utilizando JAVA

Un LDAP es un sistema de autenticación estándar utilizado por muchas compañías para controlar el acceso a aplicaciones y recursos. Por lo general se espera que cualquier nueva aplicación haga uso del LDAP para realizar la autenticación y controlar los permisos en forma unificada, la seguridad es transversal a todos los procesos que realiza una organización. Una vez regado el cuento a lo que vinimos, como conectarse a un LDAP. Lo primero que debes saber es que no se requieren librerías adicionales, JAVA en su distribución estandar ya cuenta con todo lo que necesitas. primero tres siglas que tienes que tener en cuanta. CN  = Common Name OU  = Organizational Unit DC  = Domain Component Para conectarse primero necesitas es instanciar un Objeto de la clase LdapContext, este se encargara de manejar la conexión al LDAP y las peticiones que se hagan al mismo. por consiguiente necesitara que le entregues una serie de propiedades de conexión. Esto lo haras con un Map de...

Clases anónimas JAVA (Anonymous Classes)

Código fuente articulo: https://www.dropbox.com/s/pzw44ot0ji2metl/Lambda.zip?dl=0 Las Clases anónimas en JAVA son una solución rápida para implementar una clase que se va utilizar una vez y de forma inmediata. Por ejemplo el  EventHandler  para un botón se puede implementar en la misma asignación valiendonos de la interfaz  EventHandler  que ya esta definida. Pero mejor vamos con un ejemplo mas simple. De la definición anterior concluimos dos cosas la primera es que para crear una clase anónima es necesario haber definido una interfaz, una clase o una clase abstracta. La clase anónima lo que hará sera implementar la interfaz definida o sobre escribir los métodos definidos. Para ilustrar esto utilizaremos el ejemplo del JAVA Tutorial https://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html . en este ejemplo tenemos que implementar clases que cumpliendo con la interfaz Saludo sean capaces de saludar en diferentes idiomas. El paso uno ...