
Un programa puede necesitar realizar más de una tarea al mismo tiempo, de tal forma que el programa arranque distintos hilos (threads) de ejecución, realizando acciones diferentes. Los navegadores (Explorer, Firefox, Chrome, . . .) ejecutan múltiples hilos (procesos) para llevar a cabo su trabajo, es decir la descarga y visualización de una página web.
Un hilo dispone de sus propios recursos, aunque puede compartir recurso con otros hilos, como por ejemplo un archivo. Un hilo no puede ejecutarse fuera del programa en que se encuentra, no es un programa en sí mismo. Un hilo puede ejecutar cualquier tarea, basta con indicarlo en el método run() (clase Thread), que es el que determina la actividad principal de los hilos.
Java permite crear hilos de dos formas:
1. La clase que vaya a ejecutar procesos concurrentes debe declarar que implementa la interfaz Runnable (java.lang). Esta interfaz solo define el método run(). Dentro de este método será donde se pongan las acciones (sentencias) que se ejecutarán de forma concurrente.
class ClaseConcurrente implements Runnable{
public void run(){. . .}
}
Para crear y activar un hilo basado en la clase que implementa Runnable se instancia un objeto
ClaseConcurrente y después un objeto de la clase Thread al que se le asocia el objeto ClaseConcurrente:
ClaseConcurrente objetoTarea = new ClaseConcurrente(parámetros);
Thread hilo = new Thread(objetoTarea);
Para poner en marcha el hilo:
hilo.start()
2. Declarar la clase con procesos concurrentes derivada de la clase Thread. La nueva clase hereda todos los métodos de Thread; deberá redefinir el método run(), que será donde se sitúen las acciones a ejecutar.
class ClaseConcurrente extends Thread{
public void run(){. . .}
}
Para crear un hilo basado en la clase que hereda de Thread se instancia un objeto de la clase ClaseConcurrente:
ClaseConcurrente hilo = new ClaseConcurrente(parámetros);
o bien,
Thread hilo = new ClaseConcurrente(parámetros);
Para poner en marcha el hilo:
hilo.start()
Ejemplo
Se crean dos hilos mediante una clase que implementa la interfaz Runnable.
// clase diseñada para crear hilos
public class ClaseHilo implements Runnable{
private Thread hilo;
private String entrada;
public ClaseHilo(String m){
entrada = m;
hilo = new Thread(this);
hilo.start();
}
// método en el que se definen las acciones a realizar por el hilo
public void run(){
System.out.println(«Comienza ejecución de: » + entrada);
try{
Thread.sleep(1000);
}
catch(InterruptedException er){
System.out.println(«Excepción: » + er);
}
System.out.println(«Fin de la ejecución de: » + entrada);
}
}
public class PruebaDeHilo {
public static void main(String[] args) {
ClaseHilo h1, h2;
h1 = new ClaseHilo(«Primer hilo»);
h2 = new ClaseHilo(«Segundo hilo»);
}
}
La interfaz Runnable declara el método run(). Toda clase que implemente esa interfaz debe definir dicho método. En el ejemplo, la clase ClaseHilo implementa a Runnable y define run() de tal forma que escribe una cadena y «duerme» (detiene la ejecución) durante 1000 milisegundos. El método sleep() propaga la excepción InterruptedException, que es necesario comprobar en un bloque try-catch.
El constructor de ClaseHilo se encarga de crear y activar (iniciar) la ejecución del hilo, con las sentencias:
hilo = new Thread(this);
hilo.start();
Observar que en este contexto this referencia al objeto que implementa a Runnable.
A recordar
La interfaz Runnable declara el método abstracto run(). Este no tiene argumentos, no devuelve tipo alguno. En la redefinición de run() se especifican las acciones a realizar por el hilo, o hilos, de ejecución que se creen a partir de la clase que implementa a Runnable.
Declaración: public void run()
Ejemplo
Se crean dos hilos mediante una clase que deriva de Thread. La funcionalidad es la misma que la del ejemplo anterior.
public class PruebaDeHilo {
public static void main(String[] args) {
ClaseHilo h1, h2;
h1 = new ClaseHilo(«Primer hilo»);
h2 = new ClaseHilo(«Segundo hilo»);
// se pone en marcha la ejecución de los dos hilos
h1.start();
h2.start();
}
}
// clase diseñada para crear hilos
public class ClaseHilo extends Thread{
private String entrada;
public ClaseHilo(String m){
entrada = m;
}
// método en el que se definen las acciones a realizar por el hilo
public void run(){
System.out.println(«Comienza ejecución de: » + entrada);
try{
sleep(1000);
}
catch(InterruptedException er){
System.out.println(«Excepción: » + er);
}
System.out.println(«Fin de la ejecución de: » + entrada);
}
}
En el ejemplo, la clase ClaseHilo redefine el método run() heredado de Thread. Este escribe la cadena pasada al constructor y «duerme» (detiene la ejecución) durante 1000 milisegundos. Ahora el método sleep() es heredado por ClaseHilo, se puede decir que es un método de la clase, por eso se puede llamar directamente.
Criterios a seguir para elegir cómo crear un hilo
La primera forma de crear un hilo, clase que implementa Runnable, se utiliza con más frecuencia. Permite a la clase heredar de otra clase. La creación de applets siempre se hace mediante una clase que hereda de JApplet, por ello, si en el applet se crean hilos se utilizará este método. La declaración de la clase será:
public class MiApplet extends JApplet implements Runnable
La segunda forma descrita para crear un hilo, derivar de Thread, tiene la bondad de la derivación de clases; todos los métodos de Thread son heredados por la subclase. El principal inconveniente es que solo se puede derivar de una clase, por consiguiente esta forma cierra la herencia de otras clases.