VOLUMEN 1 COLECCION PRODUCCION BOVINA . SERIE SANIDAD ANIMAL
Programación III (Java) - 08 threads
1. 8. Threads (hilos)
¿Qué es un thread?
Funcionamiento básico
Clase java.lang.Thread
Mecanismos de manipulación de threads
Ciclo de vida de un thread
Métodos sincronizados
Programación III Tema 8 - Threads
2. ¿Qué es un thread?
• Programación Tradicional
– Un procesador → Un flujo de control
– Flujo de Control = Flujo de Ejecución = Hilo de Ejecución
• Programación multihilo (multithread)
– Permite la ocurrencia simultánea de varios flujos de control
• Aun cuando siga existiendo un solo procesador
– Cada uno de ellos puede programarse independientemente
• O no. Puede compartir parte o todo el código con otros
– Pueden realizar un trabajo distinto, idéntico o complementario
• Un Thread es un hilo de ejecución que...
– se ejecuta en paralelo e “independiente” de otros hilos
– puede trabajar sobre datos propios o datos compartidos,
– puede en un momento dado pararse, reiniciarse, sincronizarse o
esperar a otros hilos.
Programación III Tema 8 - Threads
3. Un hilo NO ES un código
• Sino quien ejecuta secuencialmente ese código
Hilo Hilo Hilo Hilo
principa thread1 thread2 swing
l
main (...) { run() {
... ...
obj.m1(); o.m1();
... ...
} }
mouseClicked() {
...
test.m1();
m1 (...) { ...
... }
...
}
Programación III Tema 8 - Threads
4. Un hilo NO ES su(s)
recurso(s)
• (recursos, datos, objetos...)
hilo 1
hazTortilla() { hilo 2
...
miC =
new Cocina();
miC.cogeHuevos();
miC.cogeSarten();
miC.ponFuego();
...
}
hilo == persona ("ejecuta")
programa == acciones ("receta")
datos == objetos ("ingredientes")
Programación III Tema 8 - Threads
5. Pero ojo con los recursos
compartidos...
• Posible lío!!! (luego lo vemos)
hilo 1
hilo 2
hazTortilla() {
...
miC =
laUnicaCocina();
miC.cogeHuevos();
miC.cogeSarten();
miC.ponFuego();
...
}
Programación III Tema 8 - Threads
6. Funcionamiento básico
(1/2)
• Además entonces del hilo principal y del hilo
de swing...
– podemos crear otros hilos independientes
– que se ejecutan en paralelo al código de los
demás hilos.
• Pero... ¿qué código ejecutan los threads?
– Los threads ejecutan el código que se encuentra
dentro algún método run()...
• bien del propio thread,
• bien de otro objeto.
Programación III Tema 8 - Threads
7. Funcionamiento básico
(2/2)
• Método run() del propio Thread
– Todo thread posee un método run() que por defecto es
el código que se ejecuta cuando se pone en marcha el
Thread
• Este método por defecto se encuentra vacío sobreescribir
• Método run() de otros objetos
– El método run() no es exclusivo de los threads
– Otros objetos pueden implementar este método
• Interfaz Runnable
– Así, un thread también puede ejecutar (como un hilo de
ejecución independiente) el método run() de otros
objetos
Programación III Tema 8 - Threads
8. Clase java.lang.Thread
(1/3)
• En Java, para trabajar con Threads se utiliza
la clase Thread, del paquete java.lang.
• Constructores:
– Thread( )
• Crea un thread con nombre "Thread-"+n
– Thread( String name )
• Crea un thread con el nombre indicado como
parámetro.
– Thread( Runnable target )
• Crea un thread asociado al objeto destino.
– Combinaciones
– Uso de grupos de threads
Programación III Tema 8 - Threads
9. Clase java.lang.Thread
(2/3)
• Algunos métodos:
– static Thread currentThread()
• Devuelve el thread en curso
– String getName()
– void setName(String name)
– int getPriority()
– void setPriority(int newPriority)
• Asigna prioridades relativas
– ThreadGroup getThreadGroup()
– void run()
Programación III Tema 8 - Threads
10. Clase java.lang.Thread
(3/3)
• Creación y Puesta en marcha de Threads:
– Los Threads, como todo en Java, son objetos
– Java necesita saber que se “lanza” un nuevo hilo
Para eso se ejecuta el método start()
– Por ejemplo:
Thread miThread = new Thread();
MiThread.start();
– Así, tenemos un thread que no hace nada,
cuando se invoca el método start() no se ejecuta
ningún código porque por defecto el método
run() de un thread está vacío.
Programación III Tema 8 - Threads
11. Creando threads (1/4)
• Existen dos mecanismos para trabajar con
Threads:
– Heredar de la clase Thread
– Implementar el interface Runnable
• 1. Heredando de la clase Thread
– Se hereda de la clase Thread y se sobrescribe el
método run()
Ejemplo: ThreadHeredando.java
Programación III Tema 8 - Threads
12. Creando threads (2/4)
• Salida obtenida:
Final del main
1111111111111111111111111111111222222222222
2222222222222222222222122111111112211222111
1111111111111111111111111222222222222222222
2211122222222222211111111111111111111111111
1222222222222222222222222222
• ¿Por qué el desorden? Cada salida puede diferir
– Una vez lanzados, no sabemos cuál será el tiempo de
ejecución de los hilos
• ¿Cuántos hilos de ejecución existen en este ejemplo? 3
– El hilo de ejecución del thread t1
– El hilo de ejecución del thread t2
– El hilo de ejecución del main
Programación III Tema 8 - Threads
13. Creando threads (3/4)
• 2. Implementando el interfaz Runnable
– El interface Runnable (java.lang.Runnable) sólo tiene un
método:
public interface Runnable
{
void run();
}
– Procedimiento:
• Crear una clase que implemente el interface Runnable
• Crear un objeto de esa clase
• Vincular ese objeto a un thread
– Resultado:
• Al poner en marcha el thread, éste ejecutará el código que el
objeto posea en su método run()
Programación III Tema 8 - Threads
14. Creando threads (4/4)
• Por ejemplo:
Class MiRunnable implements Runnable {
void run() {
// haz algo
}
public static void main( String[] args )
{
Runnable objeto = new MiRunnable();
Thread hilo = new Thread( objeto );
hilo.start();
}
• hilo.start() -> objeto.run()
Programación III Tema 8 - Threads
15. Esperando a que un hilo acabe
(1)
• Otro ejemplo (HiloEjemploRunnable.java):
class HiloEjemplo implements Runnable {
static long horaInicio = System.currentTimeMillis();
int cont = 0;
int num;
HiloEjemplo( int numObjeto ) {
num = numObjeto;
}
public void run() {
while( System.currentTimeMillis()-horaInicio < 3000) {
System.out.print( num );
cont++;
}
}
public void visualizar() {
System.out.println( "Objeto num. " + num +
" - " + cont + " veces." );
} }
Programación III Tema 8 - Threads
16. Esperando a que un hilo acabe
(2)
• Posible main():
Thread[] t = new Thread [4];
HiloEjemplo[] o = new HiloEjemplo[4];
for (int i = 0; i < 4; i++) {
o[i] = new HiloEjemplo(i);
t[i] = new Thread(o[i], "Objeto-" + i);
System.out.println( "nuevo Thread() " +
(t[i]==null?"fallo":"correcto")+" - "+t[i].getName() );
}
for (int i = 0; i < 4; i++) t[i].start();
try {
for (int i = 0; i < 4; i++) t[i].join();
} catch (InterruptedException e) { }
for (int i = 0; i < 4; i++) o[i].visualizar();
• El hilo que hace el join espera a que el hilo de ese objeto
finalice
Programación III Tema 8 - Threads
17. Esperando a que un hilo acabe
(3)
• Salida obtenida:
nuevo Thread() correcto - Objeto-0
nuevo Thread() correcto - Objeto-1
nuevo Thread() correcto - Objeto-2
nuevo Thread() correcto - Objeto-3
0000000000000000000000000000000000000000011111111
1120312033333333312000000000031111111111203120311
1111111203111111111111122222222222000002333111111
1
(…)
2331111111112301233301230111111111111111122222333
3012222222222223000000111111111111111111111222222
222222222222222223000000000031203
Objeto num. 0 - 297 veces.
Objeto num. 1 - 341 veces.
Objeto num. 2 - 213 veces.
Programación III Objeto num. 3 - 302 veces.
Tema 8 - Threads
18. Ciclo de vida de un thread
(1)
Bloqueado
Esperando
Esperando-tiempo
• getState() Thread.State
– NEW
– RUNNABLE
– BLOCKED, WAITING, TIMED_WAITING
– TERMINATED
Programación III Tema 8 - Threads
19. Ciclo de vida de un thread
(2)
• Estado TIMED_WAITING:
– Método sleep()
• Método de clase (static) que permite dejar dormido
(not runnable ) al thread en curso durante un
determinado tiempo
– En este estado el thread no consume recursos no es
candidato a ser elegido por el dispatcher para su ejecución
...
Thread.sleep(1000);
...
• El thread que estaba ejecutando ese código (thread en
curso) se duerme durante 1 segundo el código no
continua ejecutándose hasta al menos 1 segundo
• La temporización no es exacta!
Programación III Tema 8 - Threads
20. Interrupción de hilos
• sleep puede lanzar InterruptedException
• Eso ocurre si algún otro hilo le interrumpe:
– Método Thread.interrupt() en el objeto a ser
interrumpido
– Fuera del sleep, la interrupción debe ser gestionada por
el programador en el run():
public void run() {
while(System.currentTimeMillis()-horaInicio<3000) {
System.out.print( num );
cont++;
if (Thread.interrupted()) break;
}
}
Programación III Tema 8 - Threads
21. Sincronización de hilos (1)
• Programar en varios hilos tiene muchas
ventajas pero algunos peligros
– ¿Y si varios acceden al mismo dato?
– ¿Y si varios ejecutan el mismo método?
• (EjemploProblemasSincronizacion.java)
• ¿Cómo solucionamos estos problemas?
esp[183452].fecundaOvulo(ov) yo.veAlBaño(unicoBaño)
Programación III Tema 8 - Threads
22. Sincronización de hilos (2)
• Modificador synchronized
• Puede aplicarse sobre:
– Un método de instancia
• En cada momento sólo habrá un hilo ejecutando un
método sincronizado sobre cada objeto
– Un método de clase
• En cada momento sólo puede haber un thread
ejecutando un método sincronizado sobre la clase o
cualquier objeto de la clase
– Un objeto tal cual - synchronized(obj)
• Bloquea a los que no pueden "entrar"
• (EjemploProblemasSincronizacion2.java)
Programación III Tema 8 - Threads
23. Sincronización de hilos (3)
• Entonces ¿mejor sincronizamos todos los
métodos?
– No. Es menos eficiente (tiempo de ejecución)
– Y puede dar lugar a interbloqueos (un gran
peligro de la programación multihilo)
• (EjemploProblemasInterbloqueos.java)
• Sincronicemos con prudencia
– Evitando interbloqueos
Programación III Tema 8 - Threads
24. Sincronización de hilos (4)
• Estado WAITING:
– Método objeto.wait()
• Causa que el thread en curso se quede esperando
– Ligado a un objeto
• Hasta que otro thread “libere”
– A ese mismo objeto
• Métodos para liberar
– objeto.notify()
» Libera uno de los que esté esperando
– objeto.notifyAll()
» Libera a todos los que estén esperando
Programación III Tema 8 - Threads
25. En resumen...
• Ciclo de vida de un thread:
– NEW - tras la construcción
– RUNNABLE - tras start()
• BLOCKED
– Esperando a entrar en un synchronized (hasta que otro
salga)
• WAITING
– wait (esperando a un notify())
– join (esperando a que termine otro/s)
• TIMED_WAITING
– sleep (esperando un tiempo)
» También wait o join con timeout
– TERMINATED - al acabar el run()
Programación III Tema 8 - Threads
26. Swing
• No es “thread-safe”
– Lo seguro es que sólo él acceda a todos los elementos
visuales (ventanas y componentes en ventanas)
• Cuidado con las llamadas a Swing desde fuera de
los eventos
• Hay tres tipos de threads para swing:
– El thread inicial (el main)
– El hilo de gestión de eventos (event dispatcher)
– Hilos de trabajo (worker threads), si procede
Programación III Tema 8 - Threads
27. Hilo inicial
• Es el del programa (main). Incluso la creación de
ventanas puede hacerse de un modo seguro:
– SwingUtilities.invokeLater( Runnable )
– "hazlo cuando puedas"
public static void main(String[] args) {
SwingUtilities.invokeLater( new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
Programación III Tema 8 - Threads
28. Hilo de gestión de eventos
• Es el hilo principal de swing
– Todos los componentes de Swing (excepto los
explícitamente "thread-safe" que son unos pocos) deben
ser llamados desde este hilo
• Deberían ser tareas pequeñas
• Deberían acabar rápido
• Si no es así, la gestión de eventos se congela y el IU no responde
– Para tareas largas hacer la gestión desde fuera del hilo
• Cuando se necesite acceder a un componente Swing,
invokeLater
• Si no se supiera si estamos o no en ese hilo:
– javax.swing.SwingUtilities.isEventDispatchThread()
Programación III Tema 8 - Threads
29. Hilos trabajadores
– Para integrarse con Swing se pueden usar threads
normales que invoquen runnables de Swing
cuando lo necesiten
• Pero también pueden usarse worker
threads
– Es una plantilla predefinida de hilo que
interactúa con Swing:
• doInBackground() como un run() que devuelve result
– Puede llamar a publish( valor )
• process( cola ) recoge la cola de publish
– LO LLAMA EL HILO DE GESTION DE EVENTOS
• done() se hace al final
Programación III – LO LLAMA EL HILO Tema 8 GESTION DE EVENTOS
DE - Threads
30. Resumen: consejos
Swing/hilos
• Sólo utilizar componentes Swing desde el
hilo de Swing salvo métodos thread-safe
– En particular, los consultores son siempre más
seguros que los modificadores
– invokeLater( r )
– invokeAndWait( r ) // síncrono
• Código de los gestores de eventos: breve
• Crear otro hilo desde el gestor si hace falta
un código largo
– A "mano" o usando SwingWorker
Programación III Tema 8 - Threads