2 Thread¶
La clase Thread¶
En Java un hilo de ejecución está representado por la clase Thread
. Si queremos crear un hilo que ejecute un determinado código deberemos definir una clase que extienda de la la clase Thread
y sobrescribir su método run()
. Dicho método será ejecutado automáticamente por el sistema cuando iniciemos la ejecución del hilo.
Debemos tener en cuenta que si simplemente instanciamos la clase Thread
usando su constructor vacío, new Thread()
estaremos creando un hilo que no ejecuta ningún código.
De cara al sistema operativo, el nuevo hilo de ejecución se crea cuando se llama a método start()
del objeto Thread
, no cuando se crea la instancia (objeto) de la clase que extiende Thread
. El entorno de ejecución de Java, después de obtener los recursos necesarios para el hilo, llama internamente al método run()
, ejecutándose de forma concurrente al hilo desde el que se llamó a start()
.
Para iniciar un objeto de dicha clase deberemos instanciarlo y llamar a su método start()
:
Nunca hagas esto
Debemos tener en cuenta que si llamamos directamente al método run()
de un objeto de una clase que extiende de Thread
NO se crea un nuevo hilo de ejecución, sino que se ejecuta su código en el mismo hilo desde el que se ha llamado.
Dentro del método run()
podemos ejecutar prácticamente cualquier código. Sin embargo los entornos visuales con UI salen restringir los hilos que pueden acceder a los componentes de la UI, permitiendo que sólo el hilo principal pueda acceder a ellos, como por ejemplo en el caso de Android.
Un hilo finaliza su ejecución en cuanto se retorne de su método run()
, ya sea por una salida anticipada mediante return
o simplemente porque se haya ejecutado su última instrucción. También puede terminar con una excepción si el código del método run()
lanza o produce una excepción que no es gestionada.
Warning
Un hilo se finaliza cuando termina de ejecutarse su método run()
Por su parte, el planificador interno de hilos puede suspender y resumir la ejecución de un hilo muchas veces durante su ciclo de vida, algunas veces atendiendo a determinadas sentencias especificadas por el desarrollador dentro del código del hilo, y que estudiaremos más adelante, como sleep()
, wait()
, notify()
, join()
, etc.
Debemos tener en cuenta que una vez que finaliza la ejecución de hilo el entorno de ejecución de Java recicla los recursos que fueron obtenidos para él, como por ejemplo el almacenamiento reservado para él, o su pila de ejecución. Esto implica que no podemos reutilizar el objeto Thread
correspondiente a un hilo ya finalizado (se ha retornado de run()
) para ejecutar alguna otra tarea.
Cuando un programa Java crea distintos hilos de ejecución no debemos olvidar que dicho programa seguirá en ejecución mientras alguno de sus hilos esté en ejecución (a no ser que se trate de un hilo demonio, como veremos más adelante). Si el hilo principal, esto es, el que ejecuta el método main()
, termina, el resto de los hilos continuarán su ejecución hasta que terminen. Si uno de los hilos usa la instrucción System.exit()
para terminar la ejecución de un programa, finalizará la ejecución de todos sus hilos.
La clase Thread
almacena ciertos atributos de información que nos pueden ayudar a identificar un hilo o conocer su estado. Veamos dichos atributos:
- ID: Identificador único para el hilo.
- Name: Nombre del hilo.
- Priority: Prioridad del hilo (de
1
a10
, donde10
es la máxima prioridad). - Status: Estado del hilo. Puede ser uno de los siguientes:
new
(nuevo),runnable
(ejecutable),blocked
(bloqueado),waiting
(esperando a otro hilo),timed waiting
(esperando a otro hilo un tiempo determinado), oterminated
(terminado).
La Máquina Virtual de Java (JVM) usa la prioridad de los hilos para seleccionar el que debe usar la CPU en cada momento y actualiza automáticamente el estado de cada hilo dependiendo de su situación. Entre todos los hilos en estado "listo", se escoge para ser ejecutado el hilo con mayor prioridad. Si hay dos o más hilos con dicha prioridad, se elige uno de ellos siguiendo un algoritmo round-robin.
Si no se especifica un nombre para el hilo, la JVM le asigna automáticamente uno con el formato Thread-XX
donde XX
es un número.
Warning
No se puede modificar los atributos ID
o Status
desde código
Debemos tener en cuenta que no es posible modificar los atributos ID
o Status
de un hilo desde código. De hecho, la clase Thread
no implementa los setters correspondientes.
El método setPriority()
puede lanzar una excepción IllegalArgumentException
si se intenta establecer una prioridad que no esté entre 1
y 10
.
Para asignar un determinado nombre a un hilo podemos pasarlo como argumento al constructor de la clase Thread
.
Proyecto Thread¶
En el siguiente proyecto crearemos una aplicación que muestra la tabla de multiplicar de los números desde el 1 al 10, usando para cada tabla un hilo de ejecución distinto. Para representar la tabla de multiplicar de un número definiremos una clase que extienda de la clase Thread
.
El código corresponde a las clases descritas en los ejemplos anterior.
Al ejecutar el proyecto podemos comprobar como el orden en que se muestran las líneas de las diferentes tablas de multiplicar no es igual al de un programa con un único hilo, e incluso puede ser diferentes en distintas ejecuciones.