Listado completo de tutoriales

100 - Hilos en Java - clase Thread


Un sistema operativo puede realizar multiprogramación al reasignar rápidamente tiempos de la CPU entre muchos programas, dando el aspecto de paralelismo, al ejecutarse concurrentemente. Aunque el verdadero paralelismos se logra con una computadora con varias CPU.

Java soporta varios hilos de ejecución. Un proceso de Java puede crear y manejar, dentro de sí mismo, varias secuencias de ejecución concurrentes o paralelos. Cada una de estas secuencias es un hilo independiente y todos ellos comparten tanto el espacio de dirección como los recursos del sistema operativo. Por lo tanto, cada hilo puede acceder a todos los datos y procedimientos del proceso, pero tiene su propio contador de programa y su pila de llamadas a métodos.

Todos los programas que hemos aprendido a desarrollar se ejecutan en forma secuencial, por ejemplo cuando llamamos a un método desde la main hasta que esta no finalice no continúan ejecutándose las instrucciones de la main.

Esta forma de resolver los problemas en muchas situaciones no será la más eficiente. Imaginemos si implementamos un algoritmo que busca en el disco duro la cantidad de archivos con extensión java, éste proceso requiere de mucho tiempo ya que el acceso a disco es costoso. Mientras esta búsqueda no finalice nuestro programa no puede desarrollar otras actividades, por ejemplo no podría estar accediendo a un servidor de internet, procesando tablas de una base de datos etc.

En el lenguaje Java se ha creado el concepto de hilo para poder ejecutar algoritmos en forma concurrente, es decir que comience la ejecución de la función pero continúe con la ejecución de la función main o la función desde donde se llamó al hilo.

Con los hilos podremos sacar ventajas en seguir la ejecución del programa y que no se bloquee en algoritmos complejos o que accedan a recursos lentos.

Otra gran ventaja con el empleo de los hilos es que los computadores actuales tienen múltiples procesadores y podremos ejecutar en esos casos hilos en forma paralela, con esto nuestros programas se ejecutarán mucho más rápido.

Los primeros problemas que resolvamos con hilos tienen por objetivo entender su creación y uso, más allá de su utilidad real.

Problema:

Mostrar el número "0" mil veces y el número "1" mil veces. Utilizar la programación secuencial vista hasta ahora.

Clase: MostrarCeroUno

public class MostrarCeroUno {

    public void mostrar0() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("0-");
    }

    public void mostrar1() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("1-");
    }

    public static void main(String[] args) {
        MostrarCeroUno m=new MostrarCeroUno();
        m.mostrar0();
        m.mostrar1();
    }
}

Si ejecutamos el programa no hay duda que primero se muestran los 1000 ceros y seguidamente se muestran los 1000 unos, ya que hasta que no finalice el método 'mostrar0' no comienza el método 'mostrar1':

java sin hilos

Problema:

Mostrar el número "0" mil veces y el número "1" mil veces. Hacer la impresión de las listas de valores en dos hilos.

Clase: MostrarCeroUnoHilo

public class MostrarCeroUnoHilo {

    public static void main(String[] args) {
        HiloMostrarCero h1 = new HiloMostrarCero();
        h1.start();
        HiloMostrarUno h2 = new HiloMostrarUno();
        h2.start();
    }
}

class HiloMostrarCero extends Thread {

    @Override
    public void run() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("0-");
    }
}

class HiloMostrarUno extends Thread {

    @Override
    public void run() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("1-");
    }
}

La ejecución del programa nos muestra la salida de números 1 y 0 en forma mezclada, esto significa que se están ejecutando en forma simultanea los dos métodos run:

java con hilos

La primer forma de crear un hilo en Java es heredar de la clase 'Thread' y sobreescribir el método 'run' donde disponemos el algoritmo que queremos que se ejecute en otro proceso de nuestro programa:

class HiloMostrarCero extends Thread {

    @Override
    public void run() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("0-");
    }
}

La clase Thread es de uso tan común en Java que se la ha incluido en el paquete 'java.lang', como sabemos dicho paquete se importa en forma automático.

Para crear un objeto de la clase 'HiloMostrarCero' codificamos lo siguiente:

        HiloMostrarCero h1 = new HiloMostrarCero();
        h1.start();

Es muy importante tener en cuenta que para arrancar el hilo debemos llamar al método 'start' de la clase 'Thread' y no llamar directamente al método 'run'. El método 'start' llama posteriormente al método 'run'.

Segunda forma de crear un hilo.

Recién vimos que podemos crear un hilo planteando una clase que herede de la clase 'Thread'. Disponemos de una segunda forma de crear hilos en Java, debemos definir un objeto de la clase Thread y una clase que implemente la interface 'Runnable'. El programa anterior con esta otra metodología queda:

public class MostrarCeroUnoHilo {

    public static void main(String[] args) {
        HiloMostrarCero h1 = new HiloMostrarCero();
        HiloMostrarUno h2 = new HiloMostrarUno();
    }
}

class HiloMostrarCero implements Runnable {
    private Thread t;

    public HiloMostrarCero() {
        t = new Thread(this);
        t.start();
    }

    @Override
    public void run() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("0-");
    }
}

class HiloMostrarUno implements Runnable {
    private Thread t;

    public HiloMostrarUno() {
        t = new Thread(this);
        t.start();
    }

    @Override
    public void run() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("1-");
    }
}

Ahora la clase 'HiloMostrarCero' no hereda de la clase 'Thread', en cambio implementa la interfaz 'Runnable':

class HiloMostrarCero implements Runnable {

Definimos como atributo un objeto de la clase 'Thread':

    private Thread t;

En el constructor creamos el hilo y le pasamos como referencia 'this' que representa el objeto que implementa la interfaz 'Runnable':

    public HiloMostrarCero() {
        t = new Thread(this);
        t.start();
    }

Como la clase 'HiloMostrarCero' especifica que implementa la interfaz 'Runnable' estamos obligados a codificar el método 'run':

    @Override
    public void run() {
        for (int f = 1; f <= 1000; f++)
            System.out.print("0-");
    }

Si ejecutamos la aplicación podemos comprobar la salida de unos y ceros no se hace en forma secuencial:

java con hilos interfaz Runnable

En la main podemos ver que se muestran 'Warnings' para las variables h1 y h2. Esto ocurre debido a que no hacemos uso de las mismas en las siguientes líneas.

En Java podemos crear un objeto de una clase y no asignarla a una variable si no vamos ha hacer uso de la misma. Luego podemos codificar la main para que no aparezcan los "Warnings" con la sintaxis:

    public static void main(String[] args) {
        new HiloMostrarCero();
        new HiloMostrarUno();
    }

Hemos visto la sintaxis de como podemos crear hilos en Java, en el concepto siguiente lo emplearemos en problemas reales donde tiene sentido su empleo.


Retornar