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
Publicar un comentario