Posts Tagged ‘Clases’

Creando hilos en Java

Sábado, septiembre 11th, 2010

En el inicio de los tiempos (para Java) habían dos formas de crear hilos:

  • La primera forma de crear un thread es simplemente extender la clase “Thread”.

    public class ThreadExample extends Thread {
        public ThreadB() {
            super("ThreadB");
        }
        public void run() {
            //Code
        }
    }
    //crea un objeto "threadExample".
    //usa "threadExample.start()" para iniciar el hilo.
    
  • La segunda forma es implementar la interfaz “Runnable”.

    public class RunnableExample implements Runnable {
        public void run() {
            //Code
        }
    }
    //crea un objeto "runnableExample".
    //usa "new Thread(runnableExample).start()" para iniciar el hilo.
    

¿Cúal de las dos formas es preferible?

La segunda forma es preferible, ya que el hecho de implementar una interface no impide extender de otra clase (o implementar otras interfaces). La composición (“composition”) es el camino “purista” a seguir. esto permite un bajo acoplamiento y da libertad de a futuro poder cambiar la forma de iniciar los hilos.

Pero… eso era el Java de antes.

Actualmente es más recomendable usar las nuevas funcionalidades proporcionada para el manejo de hilos. Es más recomendable el uso de Callables y FutureTasks. El soporte para los tiempos de espera (timeouts), para la cancelación y el manejo del conjunto de hilos (thread pooling), y las nuevas funciones de concurrencia son mucho más útiles que manejar montones de hilos en crudo y ser uno mismo el que implemente ese manejo.

La interfaz Callable es muy parecida a Runnable, con la diferencia que Callable permite devolver un objeto de la ejecución del método call (que funciona similar al run de Runnable).

Notar que Callable es una interfaz tipada, en este caso pongo un ejemplo con el tipo Object, pero bien se pudo definir el tipo de dato a regresar por call como String, Integer, o lo que desees.

	//El tipado debe ser definido por el tipo de resultado de call: Callable
	private class CallableExample implements Callable {

		/*
		 * Método sobreescrito (sin Javadoc propio)
		 * @see java.util.concurrent.Callable#call()
		 */
		@Override
		public Object call() throws Exception {
			Object obj = null;
			//implementar negocio y dar valor a "obj"
			return obj;
		}

	}

Para usos prácticos esto significa que yo estoy esperando una respuesta de Callable y que seguramente eso se traducirá en tareas síncronas:

//Colección para mantener una liga a todas las tareas
Collection tasks = new ArrayList();

//creando cada tarea
CallableExample yt1 = new CallableExample();
//Creando más tareas...

//Agregando tareas a la colección
tasks.add(yt1);
//Agregando más tareas...

//Usar el ejecutor:
ExecutorService exec = Executors.newFixedThreadPool(5);

//La lista de respuesta debe ser del tipo: List>
List> results = exec.invokeAll(tasks);

En el caso de tareas de las cuales no esperamos una respuesta, usamos la interfaz Runnable. Seguramente eso está ligado a tareas asíncronas.


/* Get an executor service that will run a maximum of 5 threads at a time: */
ExecutorService exec = Executors.newFixedThreadPool(5);

/* For all the 100 tasks to be done altogether... */
for (int i = 0; i < 100; i++) {
    /* ...execute the task to run concurrently as a runnable: */
    exec.execute(new Runnable() {
        public void run() {
            /* do the work to be done in its own thread */
            System.out.println("Running in: " + Thread.currentThread());
        }
    });
}

/* Tell the executor that after these 100 steps above, we will be done: */
exec.shutdown();

try {
    /* The tasks are now running concurrently. We wait until all work is done,
     * with a timeout of 50 seconds: */
    boolean b = exec.awaitTermination(50, TimeUnit.SECONDS);
    /* If the execution timed out, false is returned: */
    System.out.println("All done: " + b);
} catch (InterruptedException e) { e.printStackTrace(); }

Espero esto te sea de ayuda.
 
 
 
Algunas de las páginas que visité para hacer esta entrada fueron:

 
 
 

Clases internas en Java (Inner/nested classes)

Martes, septiembre 7th, 2010

Clases internas en Java (Inner/nested classes)

Una clase interna se crea si necesitamos una estrecha relación entre 2 clases diferentes (y la clase interna no tiene sentido de existir sin la presencia de la clase externa). Con esto las variables y métodos de la clase principal se encuentran visibles para la clase interna, incluso aquellos marcados como privados (private).

En forma sencilla este es un ejemplo de clase interna:

class Externa {
	class Interna { }
}

La visibilidad de las clases internas pueden ser modificadas.
Vean este ejemplo de clases internas, tomado de Sun Oracle:

public class DataStructure {
    //create an array
    private final static int SIZE = 15;
    private int[] arrayOfInts = new int[SIZE];

    public DataStructure() {
        //fill the array with ascending integer values
        for (int i = 0; i < SIZE; i++) {
            arrayOfInts[i] = i;
        }
    }

    public void printEven() {
        //print out values of even indices of the array
        InnerEvenIterator iterator = this.new InnerEvenIterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.getNext() + " ");
        }
    }

    //inner class implements the Iterator pattern
    private class InnerEvenIterator {
        //start stepping through the array from the beginning
        private int next = 0;

        public boolean hasNext() {
            //check if a current element is the last in the array
            return (next <= SIZE - 1);
        }

        public int getNext() {
            //record a value of an even index of the array
            int retValue = arrayOfInts[next];
            //get the next even element
            next += 2;
            return retValue;
        }
    }

    public static void main(String s[]) {
        //fill the array with integer values and print out only values of even indices
        DataStructure ds = new DataStructure();
        ds.printEven();
    }
}

Un detalle importante es cómo acceder a la instancia de la clase externa desde la que fue creada la clase interna usando la palabra reservada "this". Para ello basta con colocar "this" inmediatamente después del nombre de la clase:

class Externa {
	class Interna {
           System.out.println(Externa.this);
        }
}

Para el sentido contrario no es necesario una forma especial de llamada debido a que la clase externa fue la que creó instancias de la clase interna y es mediante esas referencias que uno invoca o maneja los objetos de la clase interna.

Te puede servir revisar:

http://download.oracle.com/javase/tutorial/java/javaOO/nested.html

http://download.oracle.com/javase/tutorial/java/javaOO/innerclasses.html

http://download.oracle.com/javase/tutorial/java/javaOO/summarynested.html