Está en la página 1de 25

HILO DE EJECUCIN1

Ms. Ing. Jairo E. Mrquez D.

Un thread (hilo de ejecucin), en sistemas operativos y por extensin en sistemas


virtualizados, es una caracterstica que permite a una aplicacin realizar varias tareas a
la vez (concurrentemente). Los distintos hilos de ejecucin comparten una serie de
recursos tales como el espacio de memoria, los archivos abiertos, situacin de
autenticacin, etc. Esta tcnica permite simplificar el diseo de una aplicacin que debe
llevar a cabo distintas funciones simultneamente.

Un hilo es bsicamente una tarea que puede ser ejecutada en paralelo con otra
tarea.

Los hilos de ejecucin que comparten los mismos recursos, sumados a estos recursos,
son en conjunto conocidos como un proceso. El hecho de que los hilos de ejecucin de
un mismo proceso compartan los recursos hace que cualquiera de estos hilos pueda
modificar stos. Cuando un hilo modifica un dato en la memoria, los otros hilos acceden
a ese dato modificado inmediatamente.

Lo que es propio de cada hilo es el contador de programa, la pila de ejecucin y el


estado de la CPU (incluyendo el valor de los registros).

El proceso sigue en ejecucin mientras al menos uno de sus hilos de ejecucin siga
activo. Cuando el proceso finaliza, todos sus hilos de ejecucin tambin han terminado.
Asimismo en el momento en el que todos los hilos de ejecucin finalizan, el proceso no
existe ms y todos sus recursos son liberados.

Algunos lenguajes de programacin tienen caractersticas de diseo expresamente


creadas para permitir a los programadores lidiar con hilos de ejecucin (como Java o

1
Fuente de consulta secundaria. http://es.wikipedia.org/wiki/Hilo_de_ejecuci%C3%B3n
Delphi2). Otros programas por no decir que la mayora desconocen la existencia de hilos
de ejecucin y stos deben ser creados mediante llamadas de biblioteca especiales que
dependen del sistema operativo en el que estos lenguajes estn siendo utilizados (como
es el caso del C y del C++).

Un ejemplo de la utilizacin de hilos es tener un hilo atento a la interfaz grfica (iconos,


botones, ventanas), mientras otro hilo hace una larga operacin internamente. De esta
manera el programa responde de manera ms gil a la interaccin con el usuario.
Tambin pueden ser utilizados por una aplicacin servidor para dar servicio a mltiples
clientes.

Los hilos no pueden ejecutarse ellos solos; requieren la supervisin de un proceso padre
para correr.

Dentro de cada proceso hay varios hilos ejecutndose. Por ejemplo, Word puede tener
un hilo en background chequeando automticamente la gramtica de lo que se est
escribiendo, mientras otro hilo puede estar salvando automticamente los cambios del
documento en el que se trabaja.

Como Word, cada aplicacin (proceso) puede correr varios hilos los cuales estn
realizando diferentes tareas. Esto significa que los hilos estn siempre asociados con un
proceso en particular.

Los hilos a menudo son conocidos o llamados procesos ligeros. Un hilo, en efecto, es
muy similar a un proceso pero con la diferencia de que un hilo siempre corre dentro del
contexto de otro programa. Por el contrario, los procesos mantienen su propio espacio
de direcciones y entorno de operaciones.

2
Es un entorno de desarrollo de software diseado para la programacin de propsito general con nfasis
en la programacin visual. En Delphi se utiliza como lenguaje de programacin una versin moderna de
Pascal llamada Object Pascal. En sus diferentes variantes, permite producir archivos ejecutables para
Windows, GNU/Linux y la plataforma .NET.

Un uso habitual de Delphi, aunque no el nico, es el desarrollo de aplicaciones visuales y de bases de


datos cliente-servidor y multicapas. Debido a que es una herramienta de propsito mltiple, se usa
tambin para proyectos de casi cualquier tipo, incluyendo aplicaciones de consola, aplicaciones de web
(por ejemplo servicios web, CGI, ISAPI, NSAPI, mdulos para Apache), servicios COM y DCOM, y
servicios del SO. Entre las aplicaciones ms populares actualmente destaca Skype, un programa de
telefona por IP.

Delphi inicialmente slo produca ejecutables binarios para Windows: Delphi 1 para Win16 y con Delphi
2 se introdujo Win32. En la actualidad da ms posibilidades, como son:

Delphi para Win32


Delphi para .NET
Delphi para PHP
C# para .NET
C++

Existe una versin de Delphi para sistemas Unix y Linux, denominada Kylix (de la cual existe una
versin gratuita, aunque limitada). Sin embargo Kylix fue congelado por Borland en su versin 3.00.
Los hilos dependen de un programa padre en lo que se refiere a recursos de ejecucin.
La siguiente figura muestra le relacin entre hilos y procesos.

Un programa de flujo nico o mono-hilvanado (single-thread) utiliza un nico flujo de


control (thread) para controlar su ejecucin. Muchos programas no necesitan la potencia
o utilidad de mltiples flujos de control. Sin necesidad de especificar explcitamente que
se quiere un nico flujo de control, muchos de los applets y aplicaciones son de flujo
nico.

Por ejemplo, usando Java para la aplicacin estndar de saludo:

public class HolaMundo


{
static public void main( String args[] )
{
System.out.println( "Hola Mundo!" );
}
}

Aqu, cuando se llama a main(), la aplicacin imprime el mensaje y termina. Esto ocurre
dentro de un nico thread.

La clase Thread

Es la clase que encapsula todo el control


necesario sobre los hilos de ejecucin
(threads). Hay que distinguir claramente un
objeto Thread de un hilo de ejecucin o
thread. Esta distincin resulta complicada,
aunque se puede simplificar si se considera
al objeto Thread como el panel de control de
un hilo de ejecucin (thread). La clase Thread es la nica forma de controlar el
comportamiento de los hilos y para ello se sirve de los mtodos que se exponen en las
secciones siguientes.

Mtodos de Clase

Estos son los mtodos estticos que deben llamarse de manera directa en la clase
Thread.

currentThread()

Este mtodo devuelve el objeto thread que representa al hilo de ejecucin que se est
ejecutando actualmente.

yield()

Este mtodo hace que el intrprete cambie de contexto entre el hilo actual y el siguiente
hilo ejecutable disponible. Es una manera de asegurar que nos hilos de menor prioridad
no sufran inanicin.
sleep( long )

El mtodo sleep() provoca que el intrprete ponga al hilo en curso a dormir durante el
nmero de milisegundos que se indiquen en el parmetro de invocacin. Una vez
transcurridos esos milisegundos, dicho hilo volver a estar disponible para su ejecucin.
Los relojes asociados a la mayor parte de los intrpretes de Java no sern capaces de
obtener precisiones mayores de 10 milisegundos, por mucho que se permita indicar
hasta nanosegundos en la llamada alternativa a este mtodo.

Mtodos de Instancia

Aqu no estn recogidos todos los


mtodos de la clase Thread, sino
solamente los ms interesantes, porque
los dems corresponden a reas en
donde el estndar de Java no est
completo, y puede que se queden
obsoletos en la prxima versin del
JDK, por ello, si se desea completar la
informacin que aqu se expone se ha
de recurrir a la documentacin del
interfaz de programacin de aplicacin
(API) del JDK.

start()

Este mtodo indica al intrprete de Java que cree un contexto del hilo del sistema y
comience a ejecutarlo. A continuacin, el mtodo run() de este hilo ser invocado en el
nuevo contexto del hilo. Hay que tener precaucin de no llamar al mtodo start() ms de
una vez sobre un hilo determinado.

run()

El mtodo run() constituye el cuerpo de un hilo en ejecucin. Este es el nico mtodo


del interfaz Runnable. Es llamado por el mtodo start() despus de que el hilo apropiado
del sistema se haya inicializado. Siempre que el mtodo run() devuelva el control, el
hilo actual se detendr.

stop()

Este mtodo provoca que el hilo se detenga de


manera inmediata. A menudo constituye una
manera brusca de detener un hilo,
especialmente si este mtodo se ejecuta sobre el
hilo en curso. En tal caso, la lnea
inmediatamente posterior a la llamada al
mtodo stop() no llega a ejecutarse jams, pues
el contexto del hilo muere antes de que stop()
devuelva el control. Una forma ms elegante de
detener un hilo es utilizar alguna variable que
ocasione que el mtodo run() termine de manera ordenada. En realidad, nunca se
debera recurrir al uso de este mtodo.

suspend()

El mtodo suspend() es distinto de stop(). suspend() toma el hilo y provoca que se


detenga su ejecucin sin destruir el hilo de sistema subyacente, ni el estado del hilo
anteriormente en ejecucin. Si la ejecucin de un hilo se suspende, puede llamarse a
resume() sobre el mismo hilo para lograr que vuelva a ejecutarse de nuevo.

resume()

El mtodo resume() se utiliza para revivir un hilo suspendido. No hay garantas de que
el hilo comience a ejecutarse inmediatamente, ya que puede haber un hilo de mayor
prioridad en ejecucin actualmente, pero resume() ocasiona que el hilo vuelva a ser un
candidato a ser ejecutado.

setPriority( int )

El mtodo setPriority() asigna al hilo la prioridad indicada por el valor pasado como
parmetro. 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. Como gua aproximada de utilizacin, se
puede establecer que la mayor parte de los procesos a nivel de usuario deberan tomar
una prioridad en torno a NORM_PRIORITY. Las tareas en segundo plano, como una
entrada/salida a red o el nuevo dibujo de la pantalla, deberan tener una prioridad
cercana a MIN_PRIORITY. Con las tareas a las que se fije la mxima prioridad, en
torno a MAX_PRIORITY, hay que ser especialmente cuidadosos, porque si no se hacen
llamadas a sleep() o yield(), se puede provocar que el intrprete Java quede totalmente
fuera de control.

getPriority()

Este mtodo devuelve la prioridad del hilo de ejecucin en curso, que es un valor
comprendido entre uno y diez.

setName( String )

Este mtodo permite identificar al hilo con un nombre menmnico. De esta manera se
facilita la depuracin de programas multihilo. El nombre mnemnico aparecer en todas
las lneas de trazado que se muestran cada vez que el intrprete Java imprime
excepciones no capturadas.

getName()

Este mtodo devuelve el valor actual, de tipo cadena, asignado como nombre al hilo en
ejecucin mediante setName().
Diferencias entre hilos y procesos

Los hilos se distinguen de los


tradicionales procesos en que los
procesos son generalmente
independientes, llevan bastante
informacin de estados, e interactan
slo a travs de mecanismos de
comunicacin dados por el sistema. Por
otra parte, muchos hilos generalmente
comparten otros recursos de forma
directa. En muchos de los SO que dan
facilidades a los hilos, es ms rpido
cambiar de un hilo a otro dentro del mismo proceso, que cambiar de un proceso a otro.
Este fenmeno se debe a que los hilos comparten datos y espacios de direcciones,
mientras que los procesos, al ser independientes, no lo hacen. Al cambiar de un proceso
a otro, el SO (mediante el dispatcher3) genera lo que se conoce como overhead, que es
tiempo desperdiciado por el procesador para realizar un cambio de contexto (context
switch), en este caso pasar del estado de ejecucin (running) al estado de espera
(waiting) y colocar el nuevo proceso en ejecucin. En los hilos, como pertenecen a un
mismo proceso, al realizar un cambio de hilo el tiempo perdido es casi despreciable.

Al igual que los procesos, los hilos poseen un estado de ejecucin y pueden
sincronizarse entre ellos para evitar problemas de compartimiento de recursos.
Generalmente, cada hilo tiene una tarea especfica y determinada, como forma de
aumentar la eficiencia del uso del procesador.

Estados de un hilo

Los principales estados de los hilos son: Ejecucin, Listo y Bloqueado. No tiene
sentido asociar estados de suspensin de hilos ya que es un concepto de proceso. En
todo caso, si un proceso est expulsado de la memoria principal (RAM), todos sus hilos
debern estarlo ya que todos comparten el espacio de direcciones del proceso.

Cambio de estados

Creacin: Cuando se crea un proceso se crea un hilo para ese proceso. Luego,
este hilo puede crear otros hilos dentro del mismo proceso, proporcionando un
puntero de instruccin y los argumentos del nuevo hilo. El hilo tendr su propio
contexto y su propio espacio de la columna, y pasara a la final de los listos.

Bloqueo: Cuando un hilo necesita esperar por un suceso, se bloquea (salvando


sus registros de usuario, contador de programa y punteros de pila). Ahora el
procesador podr pasar a ejecutar otro hilo que est en la final de los Listos
mientras el anterior permanece bloqueado.

Desbloqueo: Cuando el suceso por el que el hilo se bloque se produce, el


mismo pasa a la final de los Listos.

3
Parte de un programa encargada de lanzar un proceso en el servidor de un entorno cliente/servidor.
Terminacin: Cuando un hilo finaliza se liberan tanto su contexto como sus
columnas.

Ventajas de los hilos contra procesos

Los hilos son generados a partir de la creacin de un proceso, por ende, un proceso es
un hilo de ejecucin o Monohilo. Las ventajas de los hilos se dan en los Multihilos, que
es cuando un proceso tiene mltiples hilos de ejecucin los cuales realizan actividades
distintas, que pueden o no ser cooperativas entre s. Los beneficios de los hilos se
derivan de las implicaciones de rendimiento, as:

1. Se tarda mucho menos tiempo en crear un hilo nuevo en un proceso existente


que en crear un proceso. Algunas investigaciones llevan al resultado que esto es
as en un factor de 10.
2. Se tarda mucho menos en terminar un hilo que un proceso, ya que cuando se
elimina un proceso se debe eliminar el BCP (Bloque de control del proceso, o
PCB (Process Control Block)) 4 del mismo, mientras que un hilo se elimina su
contexto y pila.

4
Es un registro especial donde el SO agrupa toda la informacin que necesita conocer respecto a un
proceso particular. Cada vez que se crea un proceso el SO crea el BCP correspondiente para que sirva
como descripcin en tiempo de ejecucin durante toda la vida del proceso.

Cuando el proceso termina, su BCP es borrado y el registro puede ser utilizado para otros procesos. Un
proceso resulta conocido para el SO y por tanto elegible para competir por los recursos del sistema slo
cuando existe un BCP activo asociado a l. El bloque de control de proceso es una estructura de datos con
campos para registrar los diferentes aspectos de la ejecucin del proceso y de la utilizacin de recursos.
La informacin almacenada en un BCP incluye tpicamente algunos o todos los campos siguientes:

Identificador del proceso (Process Identificator -PID-, de sus siglas en Ingls).


Estado del proceso. Por ej. listo, en espera, bloqueado.
Contador de Programa: Direccin de la prxima instruccin a ejecutar.
Valores de registro de CPU. Se utilizan tambin en el cambio de contexto.
Espacio de direcciones de memoria.
Prioridad en caso de utilizarse dicho algoritmo para planificacin de CPU.
Lista de recursos asignados (incluyendo descriptores de archivos y sockets abiertos).
Estadsticas del proceso.
Datos del propietario (owner).
Permisos asignados.
Signals pendientes de ser servidos. (Almacenados en un mapa de bits)

Esta lista es simplemente indicativa, cada sistema operativo tiene su propio diseo de BCP, con el
conjunto de metadatos necesarios para la administracin. Puede medir desde 32 bits a 1024. Su
denominacin cambia segn el sistema operativo, por ej. en IBM se designa PSW por palabra de estado
de proceso. Difiere significativamente entre los sistemas de procesamiento por lotes (BATCH) y los
sistemas interactivos.

Algunos sistemas de multiprogramacin incluyen informacin de mantenimiento con el propsito de


facturar a los usuarios individuales el tiempo de procesador, el almacenamiento, las operaciones de E/S y
otras utilizaciones de recursos.

Una vez creado, el BCP se rellena con los atributos definidos como parmetros que se hallan en la
plantilla del proceso o que son especificados como parmetros de la llamada al SO crear_proceso. En ese
momento el sistema operativo suele asignar valores a otros campos. Por ejemplo, cuando se crea un
3. Se tarda mucho menos tiempo en cambiar entre dos hilos de un mismo proceso
4. Los hilos aumentan la eficiencia de la comunicacin entre programas en
ejecucin. En la mayora de los sistemas en la comunicacin entre procesos debe
intervenir el ncleo para ofrecer proteccin de los recursos y realizar la
comunicacin misma. En cambio, entre hilos pueden comunicarse entre s sin la
invocacin al ncleo. Por lo tanto, si hay una aplicacin que debe implementarse
como un conjunto de unidades de ejecucin relacionadas, es ms eficiente
hacerlo con una coleccin de hilos que con una coleccin de procesos separados.

Sincronizacin de hilos

Todos los hilos comparten el mismo espacio de direcciones y otros recursos como
pueden ser archivos abiertos. Cualquier
modificacin de un recurso desde un hilo afecta
al entorno del resto de los hilos del mismo
proceso. Por lo tanto, es necesario sincronizar la
actividad de los distintos hilos para que no
interfieran unos con otros o corrompan
estructuras de datos.

Una ventaja de la programacin multihilo es


que los programas operan con mayor velocidad
en sistemas de computadores con mltiples
CPUs (sistemas multiprocesador o a travs de
grupo de mquinas) ya que los hilos del programa se prestan verdaderamente para la
ejecucin concurrente. En tal caso el programador necesita ser cuidadoso para evitar
condiciones de carrera (problema que sucede cuando diferentes hilos o procesos alteran
datos que otros tambin estn usando), y otros comportamientos no intuitivos. Los hilos
generalmente requieren reunirse para procesar los datos en el orden correcto. Es posible
que los hilos requieran de operaciones atmicas para impedir que los datos comunes
sean cambiados o ledos mientras estn siendo modificados, para lo que usualmente se
utilizan los semforos5. El descuido de esto puede generar interbloqueo6.

proceso, los registros e indicadores hardware se fijan a los valores proporcionados por el
cargador/enlazador. Cada vez que un proceso queda suspendido, el contenido de los registros del
procesador es generalmente guardado en la pila, y el puntero al marco de la pila en cuestin se almacena
en el BCP. De este modo los valores de los registros son restaurados cuando el proceso es seleccionado
para ejecutarse nuevamente.

5
Un semforo es una variable especial (o tipo abstracto de datos) que constituye el mtodo clsico para
restringir o permitir el acceso a recursos compartidos (por ejemplo, un recurso de almacenamiento del
sistema o variables del cdigo fuente) en un entorno de multiprocesamiento (en el que se ejecutarn
varios procesos concurrentemente). Los semforos pueden ser usados para diferentes propsitos, entre
ellos:

Implementar cierres de exclusin mutua o locks


Barreras
Permitir a un mximo de N threads (hilos) acceder a un recurso, inicializando el semforo en N
Notificacin. Inicializando el semforo en 0 puede usarse para comunicacin entre threads sobre
la disponibilidad de un recurso
Formas de multihilos

Los sistemas operativos generalmente implementan hilos de dos maneras:

Multihilo apropiativo: permite al sistema operativo determinar cundo debe


haber un cambio de contexto. La desventaja de esto es que el sistema puede
hacer un cambio de contexto en un momento inadecuado, causando un
fenmeno conocido como inversin de prioridades y otros problemas.

Multihilo cooperativo: depende del mismo hilo abandonar el control cuando


llega a un punto de detencin, lo cual puede traer problemas cuando el hilo
espera la disponibilidad de un
recurso.

El soporte de hardware para multihilo se


encuentra disponible desde hace
relativamente poco tiempo. Esta
caracterstica fue introducida por Intel en
el Pentium 4, bajo el nombre de
HyperThreading.

Usos ms comunes

Los usos ms comunes son en tecnologas SMPP y SMS para la telecomunicaciones


aqu hay muchsimos procesos corriendo a la vez y todos requiriendo de un servicio.

- Trabajo interactivo y en segundo plano

Por ejemplo, en un programa de hoja de clculo un hilo puede estar visualizando los
mens y leer la entrada del usuario mientras que otro hilo ejecuta las rdenes y actualiza
la hoja de clculo. Esta medida suele aumentar la velocidad que se percibe en la
aplicacin, permitiendo que el programa pida la orden siguiente antes de terminar la
anterior.

- Procesamiento asncrono

Los elementos asncronos de un programa se pueden implementar como hilos. Un


ejemplo es como los software de procesamiento de texto guardan archivos temporales
cuando se est trabajando en dicho programa. Se crea un hilo que tiene como funcin
guardar una copia de respaldo mientras se contina con la operacin de escritura por el
usuario sin interferir en la misma.

6
Es el bloqueo permanente de un conjunto de procesos o hilos de ejecucin en un sistema concurrente
que compiten por recursos del sistema o bien se comunican entre ellos. A diferencia de otros problemas
de concurrencia de procesos, no existe una solucin general para los interbloqueos.
- Aceleracin de la ejecucin

Se pueden ejecutar, por ejemplo, un lote mientras otro hilo lee el lote siguiente de un
dispositivo.

- Estructuracin modular de los programas

Es un mecanismo eficiente para un programa que ejecuta una gran variedad de


actividades separadas mediante hilos que realizan cada una de ellas.

Implementaciones

Hay dos grandes categoras en la implementacin de hilos:

Hilos a nivel de usuario o ULT (user level thread).


Hilos a nivel de kernel o KLT (kernel level thread).

Hilos a nivel de usuario (ULT)

En una aplicacin ULT pura, todo el trabajo de gestin de hilos lo realiza la aplicacin
y el ncleo o kernel no es consciente de la existencia de hilos. Es posible programar una
aplicacin como multihilo mediante una biblioteca de hilos. La misma contiene el
cdigo para crear y destruir hilos, intercambiar mensajes y datos entre hilos, para
planificar la ejecucin de hilos y para salvar y restaurar el contexto de los hilos.

Todas las operaciones descritas se llevan a cabo en el espacio de usuario de un mismo


proceso. El kernel continua planificando el proceso como una unidad y asignndole un
nico estado (Listo, bloqueado, etc.).

Ventajas de los ULT

El intercambio de los hilos no necesita


los privilegios del modo kernel,
porque todas las estructuras de datos
estn en el espacio de direcciones de
usuario de un mismo proceso. Por lo
tanto, el proceso no debe cambiar a
modo kernel para gestionar hilos. Se
evita la sobrecarga de cambio de modo
y con esto el sobrecoste u overhead.
Se puede realizar una planificacin
especfica. Dependiendo de que
aplicacin sea, se puede decidir por
una u otra planificacin segn sus ventajas.
Los ULT pueden ejecutar en cualquier sistema operativo. La biblioteca de hilos
es un conjunto compartido.
Desventajas de los ULT

En la mayora de los sistemas operativos las llamadas al sistema (System calls)


son bloqueantes. Cuando un hilo
realiza una llamada al sistema, se
bloquea el mismo y tambin el resto
de los hilos del proceso.
En una estrategia ULT pura, una
aplicacin multihilo no puede
aprovechar las ventajas de los
multiprocesadores. El ncleo asigna
un solo proceso a un solo procesador,
ya que como el ncleo no interviene,
ve al conjunto de hilos como un solo
proceso.

Una solucin al bloqueo mediante a llamadas al sistema es usando la tcnica de


jacketing, que es convertir una llamada bloqueante en no bloqueante.

Hilos a nivel de ncleo (KLT)

En una aplicacin KLT pura, todo el trabajo de gestin de hilos lo realiza el kernel. En
el rea de la aplicacin no hay cdigo de gestin de hilos, nicamente un API (interfaz
de programas de aplicacin) para la gestin de hilos en el ncleo. Windows 2000, Linux
y OS/2 utilizan este mtodo. Linux utiliza un mtodo muy particular en el que no hace
diferencia entre procesos e hilos. Para Linux, si varios procesos creados con la llamada
al sistema "clone" comparten el mismo espacio de direcciones virtuales, el sistema
operativo los trata como hilos, y lgicamente son manejados por el kernel.

Ventajas de los KLT

El kernel puede planificar simultneamente mltiples hilos del mismo proceso


en mltiples procesadores.
Si se bloquea un hilo, puede planificar otro del mismo proceso.
Las propias funciones del kernel pueden ser multihilo

Desventajas de los KLT

El paso de control de un hilo a otro precisa de un cambio de modo.

Combinaciones ULT y KLT

Algunos sistemas operativos ofrecen la combinacin de ULT y KLT, como Solaris.

La creacin de hilos, as como la mayor parte de la planificacin y sincronizacin de los


hilos de una aplicacin se realiza por completo en el espacio de usuario. Los mltiples
ULT de una sola aplicacin se asocian con varios KLT. El programador puede ajustar el
nmero de KLT para cada aplicacin y mquina para obtener el mejor resultado global.
En un mtodo combinado, los mltiples hilos de una aplicacin se pueden ejecutar en
paralelo en mltiples procesadores y las llamadas al sistema bloqueadoras no necesitan
bloquear todo el proceso.

Mtodos

Lo que sigue es la lista de mtodos importantes disponibles en la clase Thread.

SN Los mtodos con Descripcin

1 public void start ()


inicia el hilo en un trazado independiente de la ejecucin, a continuacin, invoca el mtodo
run () en este objeto Thread.

2 public void run ()


Si este objeto Thread se crea una instancia con un objetivo Ejecutable independiente, el
mtodo run () se invoca en ese objeto Runnable.

3 setName public void final (String nombre)


Cambia el nombre del objeto Thread. Hay tambin un mtodo getName () para recuperar el
nombre.

4 setPriority public void final (prioridad int)


Establece la prioridad de este objeto Thread. Los valores posibles son entre 1 y 10.

5 public void setDaemon (boolean on)


Un parmetro de verdad denota este Tema como un hilo demonio.

6 final void pblico, vaya (a largo milisegundos)


El subproceso actual invoca este mtodo en un subproceso en segundo lugar, haciendo que el
hilo actual se bloquee hasta que el segundo hilo termina o pasa el nmero especificado de
milisegundos.

7 interrupcin public void ()


interrumpe este hilo, causando que para continuar la ejecucin si fue bloqueado por cualquier
motivo.

8 isAlive public final boolean ()


Devuelve true si el hilo est vivo, que es cualquier momento despus de que el hilo se ha
puesto en marcha, pero antes de que se complete.

Los mtodos anteriores se invocan en un objeto Thread en particular. Los siguientes


mtodos de la clase Thread son estticos. La invocacin de uno de los mtodos estticos
lleva a cabo la operacin en el subproceso actualmente en ejecucin.

SN Los mtodos con Descripcin

1 rendimiento public void ()


Hace que el subproceso actualmente en ejecucin para ceder el paso a cualquier otro
subproceso de la misma prioridad que estn esperando para ser programado

2 sueo public void (largo milisegundos)


hace que el subproceso actualmente en ejecucin para bloquear por lo menos el nmero
especificado de milisegundos

3 public static boolean holdsLock (Object x)


Devuelve true si el subproceso actual tiene el bloqueo en el objeto dado.

4 Tema currentThread pblica esttica ()


Devuelve una referencia al subproceso actualmente en ejecucin, que es el hilo que llama a
este mtodo.

5 dumpstack public void ()


Imprime el seguimiento de la pila para el subproceso actualmente en ejecucin, lo cual es til
cuando se depura una aplicacin multiproceso.

Ejemplos de multihilos

Ejemplo 1: Este es uno fcil

// Crear un Nuevo thread.


class NewThread implements Runnable {
Thread t;
NewThread() {
// Crear un Segundo thread
t = new Thread(this, "Demo Thread");
System.out.println("Child thread: " + t);
t.start(); // Start the thread
}

// This is the entry point for the second thread.


public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
// Let the thread sleep for a while.
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}

class ThreadDemo {
public static void main(String args[]) {
new NewThread(); // create a new thread
try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}

Que produce los siguientes resultados

Child thread: Thread[Demo Thread,5,main]


Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.
Ejemplo 2.

Crear un thread extendido

// Crear un Segundo thread extendido de un Thread


class NewThread extends Thread {
NewThread() {
// Create a new, second thread
super("Demo Thread");
System.out.println("Child thread: " + this);
start(); // Start the thread
}

// This is the entry point for the second thread.


public void run() {
try {
for(int i = 5; i > 0; i--) {
System.out.println("Child Thread: " + i);
// Let the thread sleep for a while.
Thread.sleep(500);
}
} catch (InterruptedException e) {
System.out.println("Child interrupted.");
}
System.out.println("Exiting child thread.");
}
}

class ExtendThread {
public static void main(String args[]) {
new NewThread(); // create a new thread
try {
for(int i = 5; i > 0; i--) {
System.out.println("Main Thread: " + i);
Thread.sleep(1000);
}
} catch (InterruptedException e) {
System.out.println("Main thread interrupted.");
}
System.out.println("Main thread exiting.");
}
}

El resultado que aparece es:

Child thread: Thread[Demo Thread,5,main]


Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.

Ejemplo 3.

Sea una clase que produce datos y otra que los visualiza. La productora de datos se
llama "tarea_datos" y la que los muestra se llama "tarea_vista". "tarea_vista" recibe una
referencia a "tarea_datos" para visualizar el resultado. Este ejemplo todava no contiene
hilos, su comprensin ayudar a entender como funcionan los hilos en los siguientes
ejemplos. Para acercarnos a lo que ser la explicacin sobre hilos, cada clase realiza su
labor en la funcin run(). "tarea_datos" lee un nmero de un archivo y la "tarea_vista"
lo muestra.

import java.io.*;
/****************************************
* Primera versin, sin hilos.
* En un slo hilo todo el procesamiento es secuencial y por tanto
* realiza la operacin correctamente, visualizando el dato
****************************************/
public class control01 {
public control01() {
tarea_datos01 t1 = new tarea_datos01();
tarea_vista01 t2 = new tarea_vista01( t1 );
t1.run(); // Lee dato
t2.run(); // Lo visualiza
}
public static void main(String[] args) { control01 control1 =
new control01(); }
}

/******************* Clase que obtiene el dato ******************/


class tarea_datos01 {
private double resultado = -1;

public void run() { leer_datos(); }

void leer_datos() {
try {
BufferedReader in = new BufferedReader( new
FileReader("xxx") );
resultado = Double.parseDouble( in.readLine()
);
in.close();
}
catch (Exception e) { System.out.println(
e.getMessage() ); }
}
double obt_resultado() { return resultado; }
}

/****************** Clase visualizadora *******************/


class tarea_vista01 {
private tarea_datos01 td;
tarea_vista01( tarea_datos01 td ) { this.td = td; }
public void run() { System.out.println( "Resultado: " +
td.obt_resultado() ); }
}

Lo que hace la funcin main() es:

1. Crea un objeto t1 de la clase tarea_datos01.


2. Crea un objeto t2 de la clase tarea_vista01, pasando como argumento el
objeto t1.
3. La llamada a t1.run() obtiene el dato del archivo.
4. La llamada a t2.run() implica:
I. Solicitar el dato a t1, llamando a t1.obt_resultado().
II. Visualizar el resultado.

Entonces, tarea_vista es una clase excesivamente ligera o pequea, esto solo por
ejemplo.

Puesto que el orden es secuencial y hay un nico hilo (el hilo de ejecucin de la funcin
main()), el resultado ser el esperado: imprimir por pantalla el nmero ledo del archivo.

Qu ocurre si no se cumple el orden secuencial y lgico de "I) obtener el dato y II)


visualizarlo", sino que primero se visualiza y despus se obtiene el resultado? Entonces,
el resultado que se vera por pantalla sera incorrecto, es decir, el valor por defecto: -1.
Esto es lo que nos ocurrir en la siguiente versin.

Subclases de Thread

Ahora el programa anterior se pondr en forma de multihilos, de tal forma que cada
tarea sea un hilo. Por qu usar hilos? Analice, por ejemplo, que puede interesar
simultanear la lectura de un fichero muy grande con otras tareas. Al fin y al cabo,
estamos acostumbrados a esta simultaneidad mientras se navega por la web, donde a un
tiempo puede estar descargando un fichero y abriendo una pgina.

Algunas reglas:

1. Todo hilo se inicia con la funcin start(), no con su constructor.


2. La funcin start() llama automticamente a su funcin run(), sin intervencin
del programador.
3. La funcin run() debe reescribirse sin parmetros ni devolucin de objetos.
4. En la funcin run() el programador inserta las acciones especficas del hilo.
5. No llames directamente al mtodo run(), start() lo hace por ti. La llamada
directa a run() slo ejecuta su contenido en el mismo hilo, y no en el nuevo que
se ha iniciado.

En este caso se simula una situacin tpica para usar hilos: se necesita un flujo de
control que produce los datos (por lectura y/o clculo) y otro que los consume
(visualizacin, etc.), pero no hay seguridad de que el consumo este sincronizado con la
produccin. Al aplicar un esquema de programacin multihilo vamos a enfrentarnos a
alguno de los retos de la programacin concurrente.

Entonces, los nico que se ha hecho es heredar de la clase Thread y aplicar la regla 2, es
decir, llamamos a start() y esta funcin, predefinida por Java, llama automticamente
a run():

import java.io.*;
/****************************************
* Primera versin con hilos, que muestra el resultado incorrecto (-
1).
* Ya que el hilo de visualizacin realiza su tarea antes de que
* el hilo de datos termine de leer los datos. Para simular una
'larga'
* lectura usamos sleep( milisegundos )
****************************************/
public class control02 {
public control02() {
tarea_datos02 t1 = new tarea_datos02();
tarea_vista02 t2 = new tarea_vista02( t1 );
t1.start(); // Lee dato
t2.start(); // Lo visualiza
}
public static void main(String[] args) { control02 control1 =
new control02(); }
}

/******************* Clase que obtiene dato ******************/


class tarea_datos02 extends Thread {
private double resultado = -1;

public void run() { leer_datos(); }

void leer_datos() {
try {
BufferedReader in = new BufferedReader( new
FileReader("xxx") );
sleep( 1000 );
resultado = Double.parseDouble( in.readLine()
);
in.close();
}
catch (Exception e) { System.out.println(
e.getMessage() );}
}

double obt_resultado() { return resultado; }


}

/****************** Clase visualizadora *******************/


class tarea_vista02 extends Thread {
private tarea_datos02 td;
tarea_vista02( tarea_datos02 td ) { this.td = td; }
public void run() { System.out.println( "Resultado: " +
td.obt_resultado() ); }
}

Con t1.start() se inicia el hilo que realiza la lectura. Paralelamente se


arranca t2 con t2.start(), que llama a t2.run() para visualizar el nmero. Lo que el
programa devuelve es:

Resultado: -1

Resulta evidente que se ha visualizado la variable antes de haber ledo su valor del
archivo. Necesitamos sincronizar los hilos. Necesitamos que el hilo de visualizacin no
se adelante al hilo de clculo.
Los mtodos sleep() e interrupt()

Esta es una primera aproximacin a la sincronizacin de hilos, usando sleep(), que sirve
para decirle a un hilo que se duerma durante un periodo de tiempo (medido en
milisegundos). En nuestro ejemplo modificamos tarea_datos() para que devuelva el
resultado ms tarde (y correctamente), es decir, retrasamos un hilo para "dar tiempo" a
otro para que termine su tarea:

double obt_resultado() {
try {
sleep(1050); // Duermo un poco
return resultado; // Devuelvo el dato
}
catch (InterruptedException e) {
System.out.println( e.getMessage() );
return -1;
}
}

sleep() exige el manejo de InterruptedException. Pero no es una solucin muy elegante:


el sueo debe durar 1 segundo?, o tal vez un minuto? Por cierto, nuestra llamada
invoca al mtodo de un objeto (this). Pero podemos usar sleep() como mtodo de clase
(ya que es static) en la forma:

Thread.sleep( 1050 );

Lo que estamos haciendo es dormir al hilo actual, dando as la posibilidad de ms ciclos


de procesamiento al resto de hilos.

La excepcin InterruptedException se dispara cuando otro hilo llama a interrupt() del


hilo que se quiere interrumpir. No suele usarse interrupt(), ya que los hilos suelen
interrumpirse cuando termina, llega al fin de run(). Con interrupt() despertamos a un
hilo que se encuentra dormido o bloqueado, por ejemplo por una larga operacin de
entrada/salida, por wait() o por sleep(). Hay una excepcin a la regla
sobre InterruptedException: si se llama a interrupt() cuando el hilo no est durmiendo o
esperando, no se genera InterruptedException. Puede saber si un hilo esta interrumpido
por medio de la funcin "boolean isInterrupted()":

if ( !isInterrupted() )
...
Los mtodos stop() y suspend() han sido desaconsejados por SUN.

Bloqueo de objetos (synchronized)

Uno de los problemas centrales de la programacin multihilo es manejar situaciones en


las que ms de un hilo tiene acceso a la misma estructura de datos, que es lo que sucede
normalmente en un sistema operativo. Por ejemplo, si un hilo estuviera intentando
actualizar los elementos de una lista, mientras otro est simultneamente intentando
clasificarla, su programa puede bloquearse o producir resultados incorrectos. Para evitar
este problema, debe utilizar la sincronizacin de hilos.

La forma ms sencilla de evitar que dos objetos accedan a un mtodo de un tercero al


mismo tiempo es que el primer hilo lo bloquee. Cuando un hilo mantiene un bloqueo,
otro hilo que tambin lo necesita tiene que esperar hasta que el primer hilo libera
su bloqueo. Cmo se hace? declarando mtodos sincronizados (synchronized), por
ejemplo:

synchronized void leer_datos() { ... }

Una buena metfora es pensar la situacin de bloqueo como una puerta que tiene un
cerrojo en su interior, cuando un hilo accede al mtodo cierra la puerta y bloquea la
puerta, de tal forma que otro hilo que quiera acceder a la misma se debe mantener en
espera hasta que el primero sale.

Para mantener un mtodo libre de problemas con los hilos (thread-safe), se utiliza la
palabra clave synchronized. El hilo anula el bloqueo cuando sale del ltimo mtodo
sincronizado. En nuestro caso hemos hecho que dos mtodos sean sincronizados:

synchronized void leer_datos() {


try {
BufferedReader in = new BufferedReader( new
FileReader("xxx") );
sleep( 1000 );
resultado = Double.parseDouble( in.readLine()
);
in.close();
}
catch (IOException e) { System.out.println(
e.getMessage() ); }
}

synchronized double obt_resultado() { return resultado; } //


Hemos quitado sleep() de aqui

Funciona. Visualizamos el nmero que se tena almacenado en el archivo. Por qu? El


objeto 'vista' no puede acceder a tarea_datos04.obt_resultado hasta que el objeto de
'tarea_datos04' no ha sido desbloqueado.

Hay un malentendido habitual: creer que lo que se bloquea es el mtodo. Es un error


natural, puesto que ponemos la palabra synchronized en un mtodo tendemos a pensar
que el bloqueo se produce sobre el mtodo. Es decir: ES EL OBJETO EL QUE ESTA
BLOQUEADO, NO EL METODO. Para la JVM cada objeto tiene un contador de
bloqueo, que registra el nmero de mtodos sincronizados que permanecen en
ejecucin. Cuando el contador alcanza el valor de cero, se libera el bloqueo.

Mtodos wait() y notify()

Se ha observado como se puede colocar secuencialmente los hilos por medio


de synchronized. Los mtodos wait() y notify() extienden o potencian esta capacidad.
Estos mtodos los hereda toda clase de Java, ya que estn definidos en la clase Object.
Slo pueden usarse en mtodos sincronizados.

Con wait() un hilo se queda en espera y libera el cerrojo sobre el objeto que hubiese
bloqueado (recuerde aqu la metfora de la puerta con cerrojo). Importante para evitar
esperas "eternas" (y aplicaciones "colgadas") es tener en cuenta que cuando un hilo
entra en espera no tiene posibilidad de despertarse slo, sino que depende de otro hilo
que lo despierte mediante notity(). Cuando no est seguro de cual es el hilo que debe
despertar lo ms seguro es usar notifyAll(). Las aplicaciones obedecen a una serie de
reglas:

Regla 1 (que es la synchronized): si varios hilos modifican un objeto, declare los


mtodos modificadores, as como los de slo lectura, como sincronizados. En el
ejemplo anterior:

synchronized void leer_datos() {


BufferedReader in = new BufferedReader( new
FileReader("xxx") );
....
}

synchronized double obt_resultado() { return resultado; }

Regla 2: cuando un hilo depende del estado de un objeto, debe esperar dentro del objeto
(no fuera), en un mtodo sincronizado en el que llama a wait(). Un esquema:

synchronized tipo obtener_dato() {


notifyAll(); // Despierto a los dems
while ( !condicion ) // Mientras no se cumplan
prerrequisitos para conseguir dato
wait(); // Espero
return dato; // Hago mi trabajo
}

Regla 3: cuando un hilo cambia el estado de un objeto llama a notifyAll(), ya que de esta
forma da oportunidad a los dems para despertar y comprobar si el cambio les afecta.
Un esquema:

synchronized tipo modificar_dato() {


while ( !condicion ) // Mientras no se cumplan
prerrequisitos para hacer mi trabajo
wait(); // Espero
... modifico datos ... // Hago mi trabajo
notifyAll(); // Despierto a los dems
}

Regla 4: el mtodo run() suele tener la forma siguiente (ver Horstmann y Cornell ,2003,
p. 62-63):

public void run() {


try {
while ( !interrupted() ) {
... hago mi trabajo ...
sleep( x );
}
}
catch (InterruptedException e) { }
}

El mtodo interrupted() es esttico y comprueba si el hilo actual ha sido interrumpido.


Adems su llamada reinicia el estado de "interrumpido" del hilo. A diferencia
de isInterrupted() que hace la comprobacin pero no modifica el estado "interrumpido"
del hilo.

Ver un buen ejemplo de wait() y notify() en Niemeyer y Knudsen (2000, pag. 257).

Ejemplo 4.

Este es un ejemplo que se ha adaptado de Horstmann y Cornell (2003, p. 13-17). En


este caso no se usa Swing, sino AWT (se usa la clase Applet, en vez de JFrame).
Adems, a diferencia del original, las bolas no salen de la misma posicin y su
velocidad vara.

El applet no tiene una complejidad especial:

/*********************************************************************
**
Al presionar el botn Iniciar, se crea y arranca un hilo
Cada hilo mueve una bola
**********************************************************************
**/
public class animacion_bolas extends Applet {
int origen_x = 0;
private panel_bolas pbola = new panel_bolas();
private Panel pbotones = new Panel();
Button b_iniciar = new Button( "Iniciar"); // Boton para
iniciar una animacin

/******* Inicializar el applet ********/


public void init() {
try {
jbInit();
}
catch(Exception e) { e.printStackTrace(); }
}

/**************Inicializacin de componentes ***********/


private void jbInit() throws Exception {
this.setLayout( new BorderLayout() );
pbola.setBackground(Color.cyan);
b_iniciar.addActionListener(new
animacion_bolas_b_iniciar_actionAdapter(this));
pbotones.add( b_iniciar );
add(pbola, BorderLayout.CENTER);
add(pbotones, BorderLayout.SOUTH);
}
/**** Crea la bola: (1) se la pasa al panel y (2) se la pasa al
hilo, despus start */
public void aniadir_bola() {
origen_x += 10;
if ( origen_x > 150 )
origen_x = 0;
bola b = new bola( pbola, origen_x, 0 );
pbola.add(b); // Aadir
bola a panel
hilo_de_bola thread = new hilo_de_bola( b, origen_x/5
);
thread.start();
}

/**** Gestiona el evento de pulsar botn: aade bola ****/


void b_iniciar_actionPerformed(ActionEvent e) {
aniadir_bola();
}
}

Lo nico relevante es ver que al pulsar el botn se llama a la funcin "aniadir_bola()".


En esta funcin se crea la bola (pasndole al constructor el panel de bolas y las
coordenadas de su origen. A continuacin se crea el hilo (se le pasa la bola y el periodo
de refresco medido en milisegundos). Por ltimo, se inicia el hilo con thread.start();

El panel de bolas lleva el registro (Vector) de las bolas creadas y pinta las bolas en
respuesta al evento paint:

class panel_bolas extends Panel {


private Vector lista_bolas = new Vector();

public void add( bola b ) { lista_bolas.add(b); }

public void paint(Graphics g) {


Graphics2D g2 = (Graphics2D)g;
for (int i = 0; i < lista_bolas.size(); i++) {
bola b = (bola)lista_bolas.get(i);
b.draw(g2);
}
}
}

Lo interesante es ver lo que ocurre cuando se ejecuta con start() el hilo: mueve cada
periodo de "milisegundos" la bola. Para determinar la velocidad usamos sleep().
Con sleep() no slo se consigue que duerma el hilo, sino que adems se tiene un hilo
bien diseado, ya que al dormir permite que otros hilos hagan su trabajo.

class hilo_de_bola extends Thread {


private bola b;
private int milisegundos;
public hilo_de_bola( bola abola, int milisegundos ) {
b = abola;
this.milisegundos = milisegundos;
}

public void run() {


try {
for (int i = 1; i < = 1000; i++) {
b.move(); //
Ordeno al objeto que se mueva
sleep( milisegundos ); //
Duerme al hilo
}
}
catch (InterruptedException e) { System.out.println(
e.getMessage() ); }
}
}

La clase bola es responsable de mover la posicin de la bola y dibujarla:

class bola {
private panel_bolas pbolas;
private static final int XSIZE = 15;
private static final int YSIZE = 15;
private int x = 0;
private int y = 0;
private int dx = 2; // Salto en la X
private int dy = 2; // Salto en la Y

/***** Construye la bola, asociada a un panel y unas


coordenadas de origen ******/
public bola(panel_bolas c, int origen_x, int origen_y ) {
pbolas = c;
x = origen_x;
y = origen_y;
}

/** Dibuja la bola en su posicin actual ******/


public void draw(Graphics2D g2) {
g2.fill(new Ellipse2D.Double(x, y, XSIZE, YSIZE));
}

/***** Cambio la posicin de la bola y ordeno repintar *****/


public void move() {
/*** Incremento x,y ***/
x += dx;
y += dy;

/**** Si llega al limite inferior o superior de x,


invierte el movimiento */
if (x < 0) {
x = 0;
dx = -dx;
}
if (x + XSIZE >= pbolas.getWidth()) {
x = pbolas.getWidth() - XSIZE;
dx = -dx;
}
/**** Si llega al limite inferior o superior de y,
invierte el movimiento */
if (y < 0) {
y = 0;
dy = -dy;
}
if (y + YSIZE >= pbolas.getHeight()) {
y = pbolas.getHeight() - YSIZE;
dy = -dy;
}

pbolas.repaint(); // Repintar el panel


}
}

/**** Gestin de evento de botn ******/


class animacion_bolas_b_iniciar_actionAdapter implements
java.awt.event.ActionListener {
animacion_bolas adaptee;

animacion_bolas_b_iniciar_actionAdapter(animacion_bolas
adaptee) {
this.adaptee = adaptee;
}
public void actionPerformed(ActionEvent e) {
adaptee.b_iniciar_actionPerformed(e);
}
}

El interfaz Runnable

En ocasiones puede interesar que una clase que hereda de otra (por ejemplo de Applet)
al mismo tiempo contenga el mtodo run() propio de un Thread. Pero en Java, a
diferencia de C++, no hay herencia mltiple; en esta situacin una solucin tpica de
Java es combinar la herencia (extends) con la recepcin (implements) de un interfaz. En
nuestro ejemplo ocurre que la clase hereda (extends) de Applet y reciba un interfaz que
le permita contener el mtodo deseado, run(). Para ello usamos "implements Runnable".
En el siguiente ejemplo se tiene un applet que funciona como un reloj: cada segundo se
muestra por pantalla la hora:

public class reloj extends Applet implements Runnable {

private Thread hilo;


int periodo_refresco = 1000;

/**************************************************************
**********
* run del hilo: se duerme durante un segundo
***************************************************************
********/
public void run() {
while ( hilo != null ) {
try {
Thread.sleep( periodo_refresco );
}
catch (InterruptedException e ) { return; }
repaint();
}
}

public void paint( java.awt.Graphics g ) {


g.drawString( new java.util.Date().toString( ), 10, 25
);
}
/**************************************************************
*********
* No confundirse: este mtodo es el start del applet.
* Desde aqu llamamos a start del hilo.
***************************************************************
********/
public void start( ) {
if ( hilo == null ) {
hilo = new Thread(this); // Coloco applet en
hilo
hilo.start();
}
}

/**************************************************************
*********
* Parada del applet: si la referencia al hilo no es nula: paro
el hilo.
***************************************************************
********/
public void stop( ) {
if ( hilo != null ) {
hilo.interrupt();
hilo = null;
}
}
}

Esto producira siguiente resultado:

Aspectos de la solucin:

1. El hilo es un atributo del applet. Su variable sirve como seal de control: cuando
es null significa que el hilo est parado (adems facilita la recoleccin de
basura).
2. Con start() creamos el hilo (pasamos una referencia del applet, this, al
constructor del hilo). A continuacin iniciamos el hilo, por medio de la
llamada hilo.start(). No debemos confundir el mtodo start() del applet con el
mtodo start() del hilo.
3. El mtodo run() implementa la tarea que se desea: duerme durante un segundo y
llama a repaint().
4. Cuando el applet se detiene (stop), se interrumpe el hilo. Cuando se vuelva a
iniciar el applet (start) se vuelve a crear e iniciar el hilo.

Taller
1. Correr los ejemplos citados para comprobar su estructura.
2. Con base en sus conocimientos en programacin, desarrolle un programa
que aplique el concepto de threads, y relacinelo con lo visto hasta ahora
en clase. Este programa debe estar debidamente documentado, debe
manejar por lo menos dos hilos. Usted lo puede desarrollar en el lenguaje
que maneje.