jueves, 17 de diciembre de 2015

Threads o Hilos en Java con Ejemplos

En muchas ocasiones nos interesa  que nuestro programa en Java realice varias tareas a la vez y de esta forma enriquecer la experiencia del usuario. ¿ Te imaginas un navegador web que no permita navegar por Internet hasta que no termine de descargar un archivo?



Un programa en Java se ejecuta en un Thread o Hilo principal, que es invocado cuando se ejecuta el método main. Pero nosotros podemos crear múltiples hilos, en Java no tenemos un límite máximo para cuántos podemos crear, el límite lo impone el sistema operativo y la memoria disponible para nuestro programa.




Existen 3 formas de crear hilos en Java:


  • Que nuestra clase herede la la clase Thread.
  • Que nuestra clase implemente la interface Runnable.
  • A partir de Java 8 podemos usar una referencia a un método que no tenga parámetros y devuelva void.
Veamos unos ejemplos de cómo realizar la misma tarea de las 3 formas descritas.

Nota: Java dispone de las "utilidades de concurrencia" que es un mejor método para crear y ejecutar hilos, en la mayoría de los casos, no se trabaja directamente con la clase Thread.

EJEMPLO extendiendo de la clase Thread:

Observa que lo más importante es sobrescribir el método run(),

Tarea.java
package javaapplication;

public class Tarea extends Thread{

    @Override
    public void run() {
        for (int i=1;i<=500;i++) {
            System.out.println(i);
        }
    }
    
}

JavaApplication.java
package javaapplication;

public class JavaApplication {

    public static void main(String[] args) {       
        Tarea tarea1 = new Tarea();
        Tarea tarea2 = new Tarea();
        tarea1.start();
        tarea2.start();
    }
}

Si ejecutas el ejemplo y observas la salida, verás cómo se escriben los números del 1-500 dos veces y fragmentos mezclados entre sí. Si pruebas a ejecutar una segunda vez, verás que la salida no siempre es la misma.

Java no soporta herencia múltiple, por lo que si nuestra clase ya hereda de otra, deberíamos utilizar la siguiente forma que es implementando la interfaz Runnable:

EJEMPLO implementando la interface Runnable:

Tarea.java
package javaapplication;

public class Tarea implements Runnable{

    @Override
    public void run() {
        for (int i=1;i<=500;i++) {
            System.out.println(i);
        }
    }
    
}

Observa como en este caso, es necesario crear un objeto de tipo Thread y pasar como parámetro un objeto de tipo Tarea.

JavaApplication.java
package javaapplication;

public class JavaApplication {

    public static void main(String[] args) {       
        
        Tarea tarea1 = new Tarea();
        Tarea tarea2 = new Tarea();
        Thread t1 = new Thread(tarea1);
        Thread t2 = new Thread(tarea2);
        
        t1.start();
        t2.start();
    }
}

EJEMPLO usando una referencia a un método:

A partir de Java 8 podemos realizar lo siguiente:

package javaapplication;

public class JavaApplication {

    public static void main(String[] args) {
        
        Thread t1 = new Thread(JavaApplication::print);
        Thread t2 = new Thread(JavaApplication::print);

        t1.start();
        t2.start();
    }

    public static void print() {
        for (int i = 1; i <= 500; i++) {
            System.out.println(i);
        }
    }
}

ESTABLECER PRIORIDADES EN LOS THREADS


Podemos definir prioridades en los hilos de ejecución, esto quiere decir que se asignará mayor o menor tiempo de procesador a nuestro hilo con respecto a otros.
Para indicar la prioridad se utiliza el método setPriority(int prioridad) pudiendo pasar un entero del 1 al 10, dónde 1 es la prioridad mínima y 10 la prioridad máxima.

thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.NORM_PRIORITY);
thread3.setPriority(Thread.MAX_PRIORITY);
thread4.setPriority(7);

IMPORTANTE: usar el método setPriority puede tener un comportamiento diferente según el sistema operativo.

ESTADOS DE UN THREAD.


Un hilo de ejecución puede tener 6 estados que están representados y encapsulados en la enumeración java.lang.Thread.State :


  1. NEW: El hilo no ha empezado su ejecución
  2. RUNNABLE: estado en el que el hilo se está ejecutando.
  3. BLOCKED: estado en el que el hilo esta bloqueado esperando por el acceso a un objeto.
  4. WAITING: esta esperando indefinidamente a que otro hilo termine de realizar una acción.
  5. TIMED_WAITING: parecido a waiting pero espera un tiempo determinado.
  6. TERMINATED: el hilo ha finalizado.




1 comentario: