A continuación veremos otra forma de crear hilos se esto se realizará a partir de extender la clase thread. La siguiente practica nos muestra como crear ,asignar prioridades, ejecutar y controlar la terminación de hilos, En este programa se utiliza un JFrame para mostrar tres JProgressBar cada uno tiene un hilo asociado que se encarga de llenar el progreso de la barra. Podría decirse que visualmente el programa simula una carrera entre las barras.
Programacion de Hilos
4.- Interrupción de Hilos
Normalmente un programa en java con mas de un hilo de ejecución terminará hasta que todos sus hilos hayan terminado o también podría terminar si alguno de sus hilos hace una llamada al método System.exit().
Algunas veces es necesario terminar un hilo ya sea para terminar el programa o para permitir al usuario cancelar las actividades que un hilo en particular está haciendo.
Java proporciona un mecanismo de interrupción para indicarle al un hilo que termine su ejecución.
No es tan sencillo ya que el hilo por si mismo debe tener un mecanismo para estar verificando constantemente si ha sido interrumpido ó no y tomar una decisión por sí mismo sobre qué hacer en caso de que se haya llamado al método interrupt().
El ejemplo a continuación crea un objeto Thread y después de pasados 10 segundos forza su finalización utilizando el mecanismo de interrupción.
Realice los siguientes pasos para implementar el ejemplo:
1.- Cree una clase llamada NumerosPrimos que extienda de la clase Thread.
public class NumerosPrimos extends Thread{
2.- Sobreescriba el metodo run() creando un ciclo infinito que procese números consecutivos comenzando con el 1 y determine cuales de ellos son primos.
@Override public void run() { long n=1L; while (true) { if (esPrimo(n)) { System.out.printf("numero %d es Primo \n",n); }
3. Después de procesar un numero habrá que verificar si el hilo ha sido interrumpido mediante invocar al metodo isInterrupted(). Si el método regresa Verdadero, se manda a imprimir un mensaje y se termina la ejecucion del hilo.
if (isInterrupted()) { System.out.printf("Se interrumpio el hilo"); return; } n++; } }
4. Implemente el método esPrimo() que regresará un valor booleano indicando si el numero que se recibió como parámetro es primo.
private boolean esPrimo(long num) { if (num <=2) { return true; } for (long i=2; i<num;i++) { if ((num % i)==0) { return false; } } return true; }
5.- Después de eso cree una clase que contenga un método main().
public class Main { public static void main(String[] args) {
6. Cree un objeto de la clase NumerosPrimos e invoque al método start().
Thread hilo=new NumerosPrimos(); hilo.start();
7.Espere 3 segundos e interrumpa el hilo.
try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } hilo.interrupt(); }
8. De ser necesario complete las llaves y Ejecute el ejemplo.
Programacion de Hilos
3.- Creacion y ejecucion de Hilos
En esta sección aprenderemos como crear y ejecutar un Hilo(Thread) en una aplicación en Java.
Antes que nada estableceremos que existen dos formas diferentes de poder crear un hilo en Java:
- Extendiendo la clase Thread y sobrecargando el Metodo run().
- Creando una clase que implemente la interfaz Runnable y despues creando un objeto de la clase Thread pasando el objeto Runnable como parametro.
Implementando Runnable
1.- Crear una clase llamada Calculadora que implemente Runnable
public class Calculadora implements Runnable {
2.- Declarar un atributo privado llamado numero e implementar el constructor de clase inicializando su valor .
private int number; public Calculadora(int number) { this.number=number; }
3.- Implementar el metodo run().
Este método ejecutara las instrucciones del hilo que estamos creando, en esta caso el metodo run() realizará la tabla de multiplicar del numero pasado como argumento.
@Override public void run() { for (int i=1; i<=10; i++) { System.out.printf("%s: %d * %d = %d\n",Thread. currentThread().getName(),number,i,i*number); } }
4.- Implementar la clase principal de la aplicacion.
Cree una clase llamada Main que contenga el método main()
public class Main { public static void main(String[] args) {
5.-Dentro del método main crear un ciclo for con diez iteraciones.
Dentro de este ciclo habra que crear un objeto de la clase Calculadora y crear también un objeto de la clase Thread pasando como parámetro el objeto y llamar al metodo start() del objeto tipo Thread.
for (int i=1; i<=10; i++) { Calculadora c=new Calculadora(i); //crea objeto c de tipo Calculadora Thread hilo=new Thread(c); //crea un Thread(hilo) de nombre hilo con c hilo.setName("hilo"+i); //le asigna un nombre al hilo hilo.start(); //inicia la ejecucion del hilo }
El ejemplo anterior crea e inicializa un objeto hilo cada vez que el ciclo for realiza una iteración.
Capture el código completando las llaves faltantes en el mismo y ejecute el programa para ver el funcionamiento de los hilos.
Programacion de Hilos
2.- Ciclo de Vida de los Hilos
Ciclo de Vida de un Hilo
Un hilo tiene un ciclo de vida que va desde su creación hasta su terminación.
Durante su ciclo de vida cada uno de los hilos o tareas de una aplicación puede estar en diferentes estados, la siguiente figura nos muestra un diagrama de los estados de un hilo.
Según esta figura tenemos los siguientes estados:
Estado Nuevo ó Creado
La siguiente sentencia crea un nuevo hilo de ejecución pero no lo arranca, lo deja en el estado de Nuevo o Creado:
Thread MiHilo = new MiClase();
Cuando un hilo está en este estado, es simplemente un objeto Thread vacío. El sistema no ha destinado ningún recurso para él. Desde este estado solamente puede arrancarse llamando al método start(), o detenerse definitivamente, llamando al método stop(); la llamada a cualquier otro método carece de sentido y lo único que provocará será la generación de una excepción de tipo IllegalThreadStateException.
Estado En ejecución ó Iniciado
Ahora obsérvense las dos líneas de código que se presentan a continuación:
Thread MiHilo= new MiClase(); MiHilo.start();
La llamada al método start() creará los recursos del sistema necesarios para que el hilo puede ejecutarse, lo incorpora a la lista de procesos disponibles para ejecución del sistema y llama al método run() del hilo de ejecución. En este momento se encuentra en el estado Ejecutable del diagrama. Y este estado es Ejecutable y no En Ejecución, porque cuando el hilo está aquí no esta corriendo. Muchos ordenadores tienen solamente un procesador lo que hace imposible que todos los hilos estén corriendo al mismo tiempo. Java implementa un tipo de scheduling o lista de procesos, que permite que el procesador sea compartido entre todos los procesos o hilos que se encuentran en la lista. Sin embargo, para el propósito que aquí se persigue, y en la mayoría de los casos, se puede considerar que este estado es realmente un estado En Ejecución, porque la impresión que produce ante el usuario es que todos los procesos se ejecutan al mismo tiempo.
Cuando el hilo se encuentra en este estado, todas las instrucciones de código que se encuentren dentro del bloque declarado para el método run(), se ejecutarán secuencialmente.
Estado Detenido ó Parado
El hilo de ejecución entra en estado Parado cuando alguien llama al método suspend(), cuando se llama al método sleep(), cuando el hilo está bloqueado en un proceso de entrada/salida o cuando el hilo utiliza su método wait() para esperar a que se cumpla una determinada condición. Cuando ocurra cualquiera de las cuatro cosas anteriores, el hilo estará Parado.
Por ejemplo, en el trozo de código siguiente:
Thread MiHilo = new MiClase (); MiHilo.start(); try { MiHilo.sleep( 5000 ); } catch( InterruptedException e ) { ; }
la línea de código que llama al método sleep() :
MiHilo.sleep( 5000 );
hace que el hilo se duerma durante 5 segundos. Durante ese tiempo, incluso aunque el procesador estuviese totalmente libre, MiHilo no correría. Después de esos 5 segundos. MiHilo volvería a estar en estado Ejecutable y ahora sí que el procesador podría hacerle caso cuando se encuentre disponible.
Para cada una de los cuatro modos de entrada en estado Parado, hay una forma específica de volver a estado Ejecutable. Cada forma de recuperar ese estado es exclusiva; por ejemplo, si el hilo ha sido puesto a dormir, una vez transcurridos los milisegundos que se especifiquen, él solo se despierta y vuelve a estar en estado Ejecutable. Llamar al método resume() mientras esté el hilo durmiendo no serviría para nada.
Los métodos de recuperación del estado Ejecutable, en función de la forma de llegar al estado Parado del hilo, son los siguientes:
Si un hilo está dormido, pasado el lapso de tiempo
Si un hilo de ejecución está suspendido, después de una llamada a su método resume()
Si un hilo está bloqueado en una entrada/salida, una vez que el comando de entrada/salida concluya su ejecución
Si un hilo está esperando por una condición, cada vez que la variable que controla esa condición varíe debe llamarse al método notify() o notifyAll().
Estado Muerto ó Terminado
Un hilo de ejecución se puede morir de dos formas: por causas naturales o porque lo maten (con stop()). Un hilo muere normalmente cuando concluye de forma habitual su método run().
Por ejemplo, en el siguiente trozo de código, el bucle while es un bucle finito -realiza la iteración 10 veces y termina-:
public void run() { int a=10; while( a < 20 ) { a++; System.out.println( "a= "+a ); } }
Un hilo que contenga a este método run(), morirá naturalmente después de que se complete el ciclo y run() concluya.
También se puede matar en cualquier momento un hilo, invocando a su método stop(). En el trozo de código siguiente:
Thread MiHilo = new MiClase (); MiHilo.start(); try { MiHilo.sleep( 5000 ); } catch( InterruptedException e ) { ; } MiHilo.stop();
se crea y arranca el hilo MiHilo, se duerme durante 5 segundos y en el momento de despertarse, la llamada a su método stop(), lo mata.
El método stop() envía un objeto ThreadDeath al hilo de ejecución que quiere detener. Así, cuando un hilo es parado de este modo, muere asíncronamente. El hilo morirá en el momento en que reciba ese objeto ThreadDeath.
Los applets utilizarán el método stop() para matar a todos sus hilos cuando el navegador con soporte Java en el que se están ejecutando le indica al applet que se detengan, por ejemplo, cuando se minimiza la ventana del navegador o cuando se cambia de página.
Métodos principales de un hilo ó Métodos de la Clase Thread
Metodo sleep(long)
El método sleep() provoca que el intérprete ponga al hilo en curso a dormir durante el número de milisegundos que se indiquen en el parámetro de invocación.
Una vez transcurridos esos milisegundos, dicho hilo volverá a estar disponible para su ejecución. Los relojes asociados a la mayor parte de los intérpretes de Java no serán capaces de obtener precisiones mayores de 10 milisegundos, por mucho que se permita indicar hasta nanosegundos en la llamada alternativa a este método.
Metodo start()
Este método indica al intérprete de Java que cree un contexto del hilo del sistema y comience a ejecutarlo. A continuación, el método run() de este hilo será invocado en el nuevo contexto del hilo. Hay que tener precaución de no llamar al método start() más de una vez sobre un hilo determinado.
Metodo run()
El método run() constituye el cuerpo de un hilo en ejecución. Este es el único método del interfaz Runnable. Es llamado por el método start() después de que el hilo apropiado del sistema se haya inicializado. Siempre que el método run() devuelva el control, el hilo actual se detendrá.
Metodo stop()
Este método provoca que el hilo se detenga de manera inmediata. A menudo constituye una manera brusca de detener un hilo, especialmente si este método se ejecuta sobre el hilo en curso.
En tal caso, la línea inmediatamente posterior a la llamada al método stop() no llega a ejecutarse jamás, pues el contexto del hilo muere antes de que stop() devuelva el control.
Una forma más elegante de detener un hilo es utilizar alguna variable que ocasione que el método run() termine de manera ordenada.
En realidad, nunca se debería recurrir al uso de este método.
Metodo suspend()
El método suspend() es distinto de stop(), suspend() toma el hilo y provoca que se detenga su ejecución sin destruir el hilo de sistema subyacente, ni el estado del hilo anteriormente en ejecución. Si la ejecución de un hilo se suspende, puede llamarse a resume() sobre el mismo hilo para lograr que vuelva a ejecutarse de nuevo.
Metodo resume()
El método resume() se utiliza para revivir un hilo suspendido. No hay garantías de que el hilo comience a ejecutarse inmediatamente, ya que puede haber un hilo de mayor prioridad en ejecución actualmente, pero resume() ocasiona que el hilo vuelva a ser un candidato a ser ejecutado.
Metodo setPriority( int )
El método setPriority() asigna al hilo la prioridad indicada por el valor pasado como parámetro. Hay bastantes constantes predefinidas para la prioridad, definidas en la clase Thread, tales como MIN_PRIORITY, NORM_PRIORITY y MAX_PRIORITY, que toman los valores 1, 5 y 10, respectivamente.
Metodo getPriority()
Este método devuelve la prioridad del hilo de ejecución en curso, que es un valor comprendido entre uno y diez.
Metodo setName( String )
Este método permite identificar al hilo con un nombre nemónico. De esta manera se facilita la depuración de programas multihilo. El nombre mnemónico aparecerá en todas las líneas de trazado que se muestran cada vez que el intérprete Java imprime excepciones no capturadas.
Metodo getName()
Este método devuelve el valor actual, de tipo cadena, asignado como nombre al hilo en ejecución mediante setName().
Programacion de Hilos
1.- Introduccion
Concepto de Hilo
Un hilo es un proceso que se está ejecutando en un momento determinado en nuestro sistema operativo, como cualquier otra tarea, esto se realiza directamente en el procesador.
Existen los llamados “demonios” que son los procesos que define el sistema en sí para poder funcionar y otros que llamaremos los hilos definidos por el usuario o por el programador, estos últimos son procesos a los que el programador define un comportamiento e inicia en un momento específico.
Programación multihilo
La programación multihilo es una forma especializada de multitarea, existe multitarea basada en procesos y basada en hilos:
- Basada en procesos.
Permite que se puedan ejecutar dos o más programas a la vez de manera concurrente.
- Multitarea basada en hilos.
Es la unidad mas pequeña de código que se puede seleccionar, de tal forma que un mismo programa puede realizar dos o mas tareas de forma simultanea. (Por ejemplo un editor puede dar formato y estar imprimiendo al mismo tiempo).
Programa multihilo
- Un programa multihilo contiene dos o mas partes que se pueden ejecutar de manera concurrente o simultanea.
- A cada parte del programa se le denomina como hilo (thread).
- La programación multihilo es una forma especializada de multitarea.
- Existe multitarea basada en procesos y basada en hilos.
- Basada en procesos, permite que se puedan ejecutar dos o más programas a la vez de manera concurrente.
- Multitarea basada en hilos es la unidad mas pequeña de código que se puede seleccionar, de tal forma que un mismo programa puede realizar dos o mas tareas de forma simultanea.(Por ejemplo un editor puede dar formato y estar imprimiendo al mismo tiempo).
El hilo principal.
Cuando un programa java comienza su ejecución, ya hay un hilo ejecutándose, a este hilo se le denomina normalmente hilo principal del programa, por que es el único que se ejecuta al comenzar el programa. El hilo principal es importante por dos razones:
•Es el hilo a partir del cual se crean el resto de los hilos del programa.
•Normalmente, debe ser el último que finaliza su ejecución, ya que cuando el hilo principal finaliza, el programa termina.
Comparación de un programa sin hilos y uno utilizando con hilos
En un programa de flujo unico(sin hilos) observamos una ejecución secuencial en la que para ejecutar la tarea siguiente debió haberse terminado ya la actual.
Por otra parte en un programa multihilos o de programacion concurrente existen diferentes flujos de ejecución, que pueden iniciarse en cualquier momento.
Aquí presentamos una figura en la que se puede comparar ambos flujos.