sábado, 14 de julio de 2012

5.2.1. Un ejemplo de hilos en java


Primer ejemplo

public class Hilos1{
     public static void main(String[] args){
          Hilo1 h1 = new Hilo1("Uno");
          Hilo1 h2 = new Hilo1("Dos");
          h1.start(); h2.start();
     }
}

class Hilo1 extends Thread{
     String s;

     public Hilo1(String s){
          this.s = s;
     }

     public void run(){
          for(int i=0; i<10; i++){
             System.out.println(s+" "+i);
              try{
                    sleep(Math.round(Math.random()*1000));               }catch(InterruptedException e){}
          }
     }
}
En este programa, tenemos definidas dos clases, la clase Hilos1 que es la clase principal, la cual va a crear en este caso dos hilos que arrancarán su ejecución y la clase Hilo1 que es donde programaremos el hilo a ejecutar, como puedes ver la ejecución de la clase Hilo1 extiende a Thread, como extiende a Thread, automáticamente hereda el método run pero como sabemos el método run no hace nada, ahí es donde nosotros programamos lo que queremos que se ejecute en un hilo.
El constructor de Hilo1 recibe como parámetro un string que nos va a servir para identificar que hilo se está ejecutando. Ahora veamos la programación de run, es simplemente un ciclo for que mediante una variable de control i, se ejecutará 10 veces; dentro de su ejecución simplemente va a imprimir el string que le mandamos de parámetro al constructor y después el valor de la variable i, inmediatamente después de haber ejecutado la impresión en pantalla, vamos a poner al hilo a dormir, esto lo hacemos con el método sleep, si analizas el parámetro de sleep que tiene que ser un valor de tipo long realmente es un número aleatorio entre 0 y 1 multiplicado por 1000, ¿que quiere decir esto? Que el hilo se irá a dormir por una fracción de un segundo, el valor de esta fracción será aleatorio.
Algo importante que puedes ver es que sleep está dentro de un bloque try-catch porque así lo requiere la clase Thread o mejor dicho el método sleep de la clase Thread, este método sleep arroja la interrupción InterruptedException la cual tienes que atrapar cuando utilizas sleep.
Entonces como vemos la clase Hilo1 simplemente ejecutará un ciclo durante 10 veces y dentro de ese ciclo imprimirá un letrero y dejará de competir por el CPU por una fracción de segundo.
Ahora vamos a la clase principal Hilos 1, aquí como puedes ver estamos creando dos ejemplares (objetos)  o dos instancias de la clase Hilos1, a la primera le mandamos el parámetro string "Uno" y a la segunda el parámetro string "Dos", el hecho de crear dos instancias no es todo, además debemos de arrancar los hilos, y esto se hace mandando ejecutar el método run, pero como ya vimos el método run no se ejecuta directamente, tienes que llamar a start que son las dos últimas instrucciones del método main, cuando ves h1.sart() y h2.sart() en ese momento comienza la ejecución de dos hilos, técnicamente lo que comienza es una competencia por el CPU. En la parte inferior de la filmina puedes ver la salida de una de tantas ejecuciones de este programa, como puedes ver no hay un orden en el cual se ejecutan los hilos, ambos están compitiendo por el CPU o están en estado detenidos por la llamada sleep o un tiempo aleatorio.

El mismo ejemplo, pero implementando Runnable


public class Hilos2{
      public static void main(String[] args){
          Hilo1 h1 = new Hilo1("Uno");
          Hilo1 h2 = new Hilo1("Dos");
          Thread t1 = new Thread(h1);
          Thread t2 = new Thread(h2);
          t1.start();
          t2.start();
      }
}
class Hilo1 implements Runnable{
         String s;

         public Hilo1(String s){
              this.s = s;
         }

public void run(){
     for(int i=0; i<10; i++){
          System.out.println(s+" "+i);
          try{
              Thread.sleep(Math.round(Math.random()*1000));           }catch(InterruptedException e){}
      }
  }
}

 

Ahora veamos el mismo ejemplo pero implementando runnable es decir por alguna circunstancia, nuestra clase Hilo1 no va poder extender a Thread en ese caso necesitamos que implemente runnable y cuando implementamos una interfaz nos comprometemos a programar todos los métodos de esa interfaz, en este caso la interfaz runnable solamente tiene run.
Si te fijas, la clase Hilo1 es idéntica a la clase Hilo1 del ejemplo pasado simplemente hemos sustituido extends por implement runnable, ahora veamos la clase principal que se llama Hilos2, también es muy similar a la anterior, el único detalle es que cuando creamos una instancia o un ejemplar de la clase Hilo1 todavía no hemos creado un thread que es el primer paso antes de mandar a ejecutar el método run entonces las dos instrucciones que continúan, son las que se encargan de crear instancias de la clase Thread , en el ejemplo pasado eso era automático porque al crear una instancia de Hilo1 automáticamente creabas una instancia de Thread, el otro detalle es que cuando creas una instancia de Thread tienes que asociarle un hilo o una clase que implemente runnable, en este caso los dos objetos, h1 y h2 son los que se asocian a los threads t1 y t2 respectivamente.
Y por último para arrancar los hilos simplemente mandas llamar start en cada uno de los ejemplares empleados anteriormente, y como puedes ver en la parte inferior de la filmina está una salida de la ejecución de este programa que es similar a la anterior obviamente el orden de ejecución va a ser diferente por que ambos hilos compiten por recursos y no asegura un orden.
Algo importante del archivo Hilos1.java y el archivo Hilos2.java se encuentran en los archivos auxiliares que bajarás de la red (ver ejercicio),  es que cuando ejecutes Hilos1 compílalo previamente y cuando ejecutes Hilos2 vuelve a compilar los dos, la razón es que ambos archivos tienen definida una clase Hilo1, lo que pasaría si no recompilas Hilos2 antes de ejecutarlo y previamente compilaste Hilos1, la clase que se compiló es Hilo1 pero que extiende a Thread y no Hilo1 que implementa runnable, esto está hecho en forma intencional para que veas que se generan dos clases en el momento de compilación a pesar de que es solamente un archivo fuente. Así es que por favor antes de ejecutar cada uno de los programas compílalos.

No hay comentarios:

Publicar un comentario