20151021
dit
UPM
Programación concurrente —
Hebras
Juan Antonio de la Puente <
[email protected]>
Algunos derechos reservados. Este documento se distribuye bajo licencia
Crea9ve Commons Reconocimiento-NoComercial-Compar9rIgual 3.0 Unported.
hBp://crea9vecommons.org/licenses/by-nc-sa/3.0/deed.es
Referencias
• Scott Oaks & Henry Wong
Java Threads
O'Reilly Media; 3rd ed (2004)
• Kathy Sierra & Bert Bates
Head First Java, ch. 15
O'Reilly Media; 2nd ed (2005)
• Mordechai Ben-Ari
Principles of Concurrent and Distributed
Programming
Addison-Wesley; 2nd ed (2006)
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
2
Programas concurrentes
Programas secuenciales y concurrentes
• Los programa que hemos visto hasta ahora son
programas secuenciales
‣ ejecutan una operación detrás de otra (en secuencia)
- aunque el orden puede variar (alternativas, bucles, etc).
‣ sólo hacen una cosa a la vez
- sólo hay un flujo de ejecución
• A veces necesitamos que un programa haga varias
cosas al mismo tiempo
‣ varias tareas o actividades que progresan en paralelo
- en Java se llaman threads o hebras
• Estos programas se llaman programas concurrentes
‣ tienen varios flujos de ejecución
- cada uno de ellos ejecuta una secuencia de operaciones
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
4
Ejecución concurrente y hebras
programa
secuencial
programa
concurrente
hebra
hebra
hebra
operación
operación
operación
operación
operación
operación
operación
operación
operación
operación
operación
operación
...
...
...
...
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
5
¿Cómo funciona?
• En un sistema con varios procesadores se puede
ejecutar cada tarea en un procesador
‣ ejecución simultánea (paralelismo físico)
T1
T2
operación
operación
operación
operación
operación
operación
operación
operación
operación
operación
• En un monoprocesador se intercalan las
operaciones de las tareas
‣ multiplexado en tiempo (paralelismo lógico)
T1, T2
operación
operación
operación
operación
operación
• La máquina virtual (o el sistema operativo) se
encarga de los detalles
• Desde un punto de vista lógico son equivalentes
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
t
t
6
Aplicaciones
• Interfaces de usuario reactivas
‣ atención a sucesos asíncronos
‣ gestión de ventanas, widgets, etc.
• Servidores
‣ atención a múltiples clientes
‣ gestión de protocolos de comunicación
• Mejoras de prestaciones
‣ ejecución en multiprocesadores
• Cálculos complejos
‣ ejecución de algoritmos en paralelo
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
7
Ejemplo
• Programa con dos
actividades:
‣ escribir la hora cada 1 s
‣ emitir un sonido cuando se
pulsa la tecla intro
• Sería muy complicado
hacerlo con un programa
secuencial
‣ la tecla se puede pulsar en
cualquier momento
- es un suceso asíncrono
- difícil de mezclar con la escritura
de la hora
• Mejor con dos hebras
programa
hora
sonido
espera 1 s
espera tecla
escribe hora
emite
sonido
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
8
Ejemplo (continuación)
/* hora */
while(true) {
sleep(1000);
System.out.println(
new Date().toString());
}
/* linea */
while(true) {
nextLine();
beep();
}
• Veremos el programa completo más adelante
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
9
Hebras (threads) en Java
Threads en Java
• En Java las actividades concurrentes se llaman
threads (hebras, hilos)
• Se crean extendiendo la clase Thread
class Tarea extends Thread {
@Override
public void run() {…} // código concurrente
}
Tarea t = new Tarea();
‣ Es obligatorio redefinir el método run()
- contiene el código que se ejecuta concurrentemente con otras hebras
ADSW – Concurrencia
© 2014 Juan A. de la Puente
11
Arrancar una hebra
• Hay que arrancar la ejecución de cada hebra para
que empiece a ejecutarse
‣ método start()
• Ejemplo
Tarea t = new Tarea(); // se crea la hebra t
...
t.start(); // se empieza a ejecutar
‣ ahora se ejecutan a la vez el método t.run() y el método
main()
ADSW – Concurrencia
© 2014 Juan A. de la Puente
12
Hebras en un programa
• ¿Cuántas hebras hay en un programa?
‣ una hebra inicial que ejecuta el método main()
‣ todas las que se arranquen en el programa con start()
‣ la máquina virtual y la interfaz gráfica pueden crear
hebras adicionales
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
13
Terminación de hebras y programas
• Una hebra termina cuando termina el método run()
‣ o cuando se fuerza su terminación mediante una interrupción
- lo veremos más tarde
• Un programa termina cuando terminan todas sus
hebras
‣ cuando termina main() y todas las demás hebras que hayan
arrancado en el programa
• El programa también termina si
‣ se hace exit() desde alguna hebra
‣ se lanza una excepción que se propaga fuera de run() o
main()
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
14
Estados de las hebras
preempt
nueva
start
t.start();
lista
dispatch
en
ejecución
Thread t = new Tarea();
resume
end run
suspend
bloqueada
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
15
Ejemplo: Hora
import java.util.*;
public class Hora extends Thread {
@Override
public void run() { /* código concurrente */
try {
while (true) {
sleep(1000); /* esperar 1000 ms */
System.out.println(new Date().toString());
}
} catch (InterruptedException e) {
return; /* terminar esta hebra */
}
}
}
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
16
Ejemplo: Sonido
import java.awt.Toolkit;
import java.util.Scanner;
public class Sonido extends Thread {
@Override
public void run() { /* código concurrente */
}
Scanner sc = new Scanner(System.in);
while(true) {
}
sc.nextLine();
Toolkit.getDefaultToolkit().beep();
}
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
17
Ejemplo: Reloj
public class Reloj {
}
Hora hora = new Hora () ;
Sonido sonido = new Sonido();
hora.start();
sonido.start();
public static void main(String[] args) {
}
}
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
18
Ejercicio
• Creación y activación de hebras
‣ Importar el proyecto Threads del repositorio
https://github.com/ALED-UPM/Tema3
‣ Ejecutar el programa Reloj
‣ Añadir una hebra que escriba “Hola” en el terminal cada 5 s,
y volver a ejecutar el programa con esta modificación
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
19
Otras formas de crear
hebras
La clase java.lang.Thread
public class Thread implements Runnable {
/* constructores */
public Thread();
public Thread(Runnable target);
/* código concurrente */
void run();
/* arrancar la ejecución */
void start();
/* suspender la ejecución durante un tiempo */
static native void sleep(long millis)
throws InterruptedException;
/* esperar que termine la hebra */
void join() throws InterruptedException;
/* interrumpir la ejecución de la hebra */
public void interrupt() throws SecurityException;
...
}
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
21
La interfaz Runnable
• Java sólo admite herencia simple
‣ si se hereda de Thread no se puede heredar de otra clase
• java.lang.Runnable es una interfaz que incluye el
método run
‣ permite crear hebras sin heredar de Thread
public interface Runnable {
public void run ();
}
class Actividad implements Runnable {
public void run() {…}
}
Thread t = new Thread(new Actividad());
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
22
Ejemplo: Hora2
import java.util.*;
public class Hora2 implements Runnable {
public void run() {
try {
while (true) {
Thread.sleep(1000);
System.out.println(new Date().toString());
}
} catch (InterruptedException e) {
return;
}
}
}
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
23
Ejemplo: Reloj2
public class Reloj2 {
public static void main(String[] args) {
Runnable escribeHora = new Hora2();
/* no es un thread */
Thread hora = new Thread(escribeHora);
hora.start();
/* ahora sí */
...
}
}
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
24
Objetos Runnable internos
public class Reloj3 {
public static void main(String[] args) {
Runnable escribeHora = new Runnable () {
public void run() {...}
};
new Thread(escribeHora).start();
...
}
}
• El método run queda oculto
‣ no se puede invocar desde fuera
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
25
Método run interno con Thread
public class Reloj4 {
public static void main(String[] args) {
Thread hora = new Thread () {
public void run() {
...
}
};
hora.start();
...
}
}
• Otra forma de declarar el método run para que
quede oculto
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
26
Más compacto todavía
public class Reloj5 {
public static void main(String[] args) {
new Thread () {
public void run() {
...
}
}.start();
...
}
}
Programación concurrente — Hebras
© 2014 Juan A. de la Puente
27
Interrupciones
Método interrupt
• Método de la clase Thread
• Uso habitual: despertar asíncronamente a una hebra
bloqueada
• Si la hebra está bloqueada en un wait, join o sleep,
se eleva la excepción InterruptedException
‣ Incluir la sentencia de bloqueo un bloque try/catch
‣ Indicar que el
Comentarios de: Programación concurrente - Hebras (0)
No hay comentarios