En Java, los hilos comparten el mismo espacio de memoria. Incluso comparten gran parte del

entorno de ejecución, de modo que la creación de nuevos hilos es mucho más rápida que la

creación de nuevos procesos. La ventaja que proporcionan los hilos es la capacidad de tener más

de un camino de ejecución en un mismo programa. Así, con un único proceso, ejecutándose una

JVM (Java Virtual Machine), habrá siempre más de un hilo, cada uno con su propio camino de

ejecución.

En cuanto al proceso de creación de hilos, son dos los mecanismos que nos permiten

llevarlo a cabo en Java: implementando la interfaz Runnable, o extendiendo la clase Thread,

esto es, creando una subclase de esta clase.

Lo más habitual es crear hilos implementando la interfaz Runnable, dado que las

interfaces representan una forma de encapsulamiento del trabajo que una clase debe realizar.

Así, se utilizan para el diseño de requisitos comunes a todas las clases que se tiene previsto

implementar. La interfaz define el trabajo, la funcionalidad que debe cubrirse, mientras que la

clase o clases que implementan la interfaz realizan dicho trabajo (cumplen esa funcionalidad).

Todas las clases o grupos de clases que implementen una cierta interfaz deberán seguir las

mismas reglas de funcionamiento.

El otro mecanismo de creación de hilos, como ya hemos dicho, consistiría en la creación

previa de una subclase de la clase Thread, la cual podríamos instanciar después.

Por ejemplo,

class Mi Thread extends Thread {

public void run() {

. . .

}

}

se corresponde con la declaración de un clase, Mi Thread, que extiende la clase Thread,

sobrecargando el método Thread.run heredado con su propia implementación.

González et al.

5

Es en el método run donde se implementa el código correspondiente a la acción (la tarea)

que el hilo debe desarrollar . El método run no es invocado directa o explícitamente (a menos

que no quieras que se ejecute dentro de su propio hilo). En lugar de esto, los hilos se arrancan

con el método start, se suspenden con el método suspend, se reanudan con el método

resume, y se detienen con el método stop (el cual supone también la muerte del hilo y la

correspondiente excepción Thread Death?), como ya explicaremos en el apartado de Estado y

Control de Hilos. Un hilo suspendido puede reanudarse en la instrucción del método run en la

que fue suspendido.

En el caso de crear un hilo extendiendo la clase Thread, se pueden heredar los métodos y

variables de la clase padre. Si es así, una misma subclase solamente puede extender o derivar

una vez de la clase padre Thread. Esta limitación de Java puede ser superada a través de la

implementación de Runnable. Veamos el siguiente ejemplo:

public class Mi Thread implements Runnable {

Thread t;

public void run() {

// Ejecución del thread una vez creado

}

}

En este caso necesitamos crear una instancia de Thread antes de que el sistema pueda

ejecutar el proceso como un hilo. Además, el método abstracto run que está definido en la

interfaz Runnable tiene que implementarse en la nueva clase creada.

La diferencia entre ambos métodos de creación de hilos en Java radica en la flexibilidad con

que cuenta el programador, que es mayor en el caso de la utilización de la interfaz Runnable.

Sobre la base del ejemplo anterior, se podría extender la clase Mi Thread a continuación, si

fuese necesario. La mayoría de las clases creadas que necesiten ejecutarse como un hilo

implementarán la interfaz Runnable, ya que así queda cubierta la posibilidad de que sean

extendidas por otras clases.

Por otro lado, es un error pensar que la interfaz Runnable está realizando alguna tarea

mientras un hilo de alguna clase que la implemente se está ejecutando. Es una interfaz, y como

tal, sólo contiene funciones abstractas (concretamente una única, run), proporcionando tan solo

una idea de diseño, de infraestructura, de la clase Thread, pero ninguna funcionalidad. Su

declaración en Java tiene el siguiente aspecto:

package Java.lang;

public interfaz Runnable {

public abstract void run() ;

}

Comentados los aspectos más importantes de la interfaz Runnable, veamos ahora la

definición de la clase Thread, de la cual podemos deducir lo que realmente se está haciendo:

public class Thread implements Runnable {

public void run() {

Java Threads (Hilos en Java)

6

if( tarea != null )

tarea.run() ;

}

…}

Se deduce, por tanto, que la propia clase Thread de Java también implementa la interfaz

Runnable. Observamos que en el método run de Thread se comprueba si la clase con que

se está trabajando en ese momento (tarea), que es la clase que se pretende ejecutar como hilo,

es o no nula. En caso de no ser nula, se invoca al método run propio de dicha clase.

Control de un hilo

Arranque de un hilo

En el contexto de las aplicaciones, sabemos que es main la primera función que se invoca tras

arrancar, y por tanto, lógicamente, es el lugar más apropiado para crear y arrancar otros hilos.

La línea de código:

t1 = new Test Th( “Thread 1″,(int)(Math.random()*2000) );

siendo Test Th una subclase de la clase Thread (o una clase que implemente la interfaz

Runnable) crea un nuevo hilo. Los dos argumentos pasados, sin mayor relevancia, satisfarán

el prototipo del constructor de la clase y se utilizarán para la inicialización del objeto.

Al tener control directo sobre los hilos, tenemos que arrancarlos explícitamente. Como ya se

comentó anteriormente, es la función miembro start la que nos permite hacerlo. En nuestro

ejemplo sería:

t1.start();

start, en realidad es un método oculto en el hilo que llama al método run.

Manipulación de un hilo

Si todo fue bien en la creación del objeto Test Th (t1), éste debería contener un hilo, una traza

de ejecución válida, que controlaremos en el método run del objeto.

El cuerpo de esta función miembro viene a ser el cuerpo de un programa como ya los

conocemos. Digamos que es la rutina main a nivel de hilo. Todo lo que queremos que haga el

hilo debe estar dentro del método run. Cuando finalice run, finalizará también el hilo que lo

ejecutaba.

Suspensión de un Hilo

La función miembro suspend de la clase Thread permite tener un control sobre el hilo de

modo que podamos desactivarlo, detener su actividad durante un intervalo de tiempo

indeterminado, a diferencia del uso de la llamada al sistema sleep, que simplemente lleva al

hilo a un estado de “dormido”, y siempre durante un número de milisegundos concreto.

Este método puede resultar útil si, construyendo un applet con un hilo de animación,

queremos permitir al usuario detener (que no finalizar) la animación, hasta que éste decida

reanudarla.

Este método no detiene la ejecución permanentemente. El hilo es suspendido

indefinidamente y para volver a activarlo de nuevo necesitamos realizar una invocación a la

función miembro resume.

González et al.

9

Parada de un Hilo

Ya conocemos los métodos de control de hilos que nos permiten arrancarlos, suspenderlos y

reanudarlos. El último elemento de control que se necesita sobre hilos es el método stop,

utilizado para terminar la ejecución de un hilo de forma permanente:

t1.stop();

Señalar que esta llamada no destruye el hilo, sino que detiene su ejecución, y ésta no puede

reanudarse con el método start. Cuando se desasignen las variables que se usan en el hilo, el

objeto hilo (creado con new) quedará marcado para eliminarlo y el garbage collector

(recolector de basura de Java) se encargará de liberar la memoria que utilizaba.

Tiene sentido su utilidad, por ejemplo, en aplicaciones complejas que necesiten un control

sobre cada uno de los hilos que se lancen.

Por último, un método de control de hilos que nos permite comprobar si una instancia está

viva (el hilo se ha arrancado y aún no se ha detenido) o no (bien no se arrancó; bien ya finalizó).

Estamos hablando de la función miembro isAlive.

t1.isAlive();

Devolverá true en caso de que el hilo t1 esté vivo, es decir, ya se haya llamado a su

método run y no haya sido parado con un stop ni haya terminado el método run en su

ejecución. En otro caso, lógicamente, devolverá false.

MARTIN TAPIA GOMEZ TEC DE ZITACUARO