Title: Sincronizaci
1Sincronización de Threads en Java
- Josep Joan Ribas Prats
- Sergio Liminiana Bernat
2Introducción
- Los threads o hilos de ejecución son segmentos de
código de un programa que se ejecutan
secuencialmente de modo independiente de otras
partes del programa. - Un proceso puede estar constituido por uno o mas
threads. - Un thread esta compuesto por
- Una CPU virtual
- El código que ejecuta el procesador
- Los datos sobre los que trabaja el código
- Dos threads comparten código si ejecutan código
de objetos que pertenecen a la misma clase.
3Introducción (II)
- Los datos pueden ser o no compartidos por
diferentes threads. Eso ocurre cuando tienen
acceso a un objeto común.
4Para qué?
- Los threads se utilizan para aislar y coordinar
tareas. - Sin el uso de threads hay aplicaciones que son
casi imposibles de programar - Las que tienen tiempos de espera importantes
entre etapas - Las que consumen muchos recursos de CPU e impiden
que el procesador atienda simultáneamente otros
eventos o peticiones del usuario
5Tipos.
- Tipos de threads que pueden aparecer en una
aplicación - Threads completamente independientes, que
realizan tareas no relacionadas. Éste es el caso
más sencillo y no requiere ninguna programación
especial. - Threads que trabajan en una misma tarea, pero sin
interferir ni intercambiar relación entre ellos.
Por ejemplo, threads que colaboran en el producto
de dos matrices ocupándose cada una de ellas de
calcular ciertas filas de la matriz producto.
6Tipos(II).
- Threads que utilizan recursos de modo mutuamente
exclusivo, aunque sin tener que coordinar sus
actividades. Por ejemplo, threads que actualizan
o leen registros de una base de datos y que no
pueden actuar simultáneamente. - Threads que deben de coordinar sus actividades,
de modo que una de ellas no puede empezar o
continuar hasta que la otra haya realizado su
tarea. Los ejemplos más típicos son los de tipo
productor-consumidor, en el que este último tiene
que esperar para realizar su función a que el
productor le haya preparado los datos y le avise
de esa circunstancia.
7Creación.
- Hay dos modos de conseguir threads en Java. Una
es extender la clase Thread, la otra es
implementando la interface Runnable.
8Creación extendiendo la clase Thread
- El nuevo thread se crea extendiendo la clase
Thread y redefiniendo el metodo run(). - Exemple
- public class MyThread extends Thread
- public void run()
- // código propio del thread
-
-
- public static void main()
- Thread t new MyThread()
- t.start
-
9Creación implementando la interface Runnable
- El constructor de la clase Thread recibe un
argumento que debe ser una instancia de una clase
que implementa la interface Runnable,
implementando el metodo run() .
10Creación implementando la interface Runnable(II)
- Ejemplo
- public class ThreadTest
- public static void main(String args
- Xyz r new XYZ()
- Thread t new Thread( r )
-
-
- class Xyz implements Runnable
- int i
- public void run()
- while (true)
- System.out.println(Hello i)
- if (i50) break
-
-
-
11Qué mecanismo usar?
- Implementar la interfaz Runnable
- Mejor diseño orientado a objetos. La clase thread
solo deberá ser extendida cuando se pretenda
modificar o extender el comportamiento de dicho
modelo de ejecución. - Herencia simple. Debido a la tecnología de Java
no es posible extender una clase cuando ésta ya
ha sido extendida a la clase thread - Extender la clase Thread
- Código más simple. En el método run la referencia
this apunta a la instancia del thread actual
12Estados de un thread.
Otherwise Blocked
New
sleep() timeout thread join() interrupt()
start()
sleep() join()
run()
Runnable
Running
Dead
synchronized()
wait()
lock available
Blocked in objects wait() pool
Blocked in objects lock pool
notify() interrupt()
13Estados de un thread (II).
- Nuevo (New) El thread ha sido creado pero no
inicializado (no se ha ejecutado todavía el
método start()), por lo que todavía no puede
ejecutarse. - Ejecutable (Runnable) El thread puede estar
ejecutándose, siempre y cuando se le asigne
tiempo de CPU. (Scheduler)
14Estados de un thread (III).
- Muerto (Dead) La forma habitual de morir en un
thread es finalizando de ejecutar el método
run(), bien por terminar su tarea, bien dejando
de cumplir una condición chequeada en dicho
método. - Bloqueado (Blocked o Not Runnable) El thread
podría estar ejecutándose, pero hay algo que lo
impide, como por ejemplo una operación de E/S.
Mientras un thread esté en este estado, no se le
asigna tiempo de CPU.
15Planificación de threads.
- La planificación de ejecución de threads se basa
en el modelo de prioridades y no utiliza el
modelo de segmentación por segmentos de tiempo. - Un thread continuará ejecutandose en la CPU hasta
pasar a un estado que no le permita seguir en
ejecución. Se debe asegurar que el thread permite
la ejecución de otros threads, esto se puede
conseguir mediante llamadas al método sleep().
16Planificación de threads(II).
- Ejemplo
- public class Xyz implements Runnable
- public void run()
- While(true)
- // código del propio thread
- try
- // permitimos la ejecución de otros threads
- Thread.sleep(10)
- catch(InterruptedException e)
- // otro thread despierta a este thread
-
-
-
- Los threads pueden invocar al método interrupt()
de otros threads para reanimarlos.
17Planificación de Threads(III).
- Otro método para permitir la ejecución de otros
threads es el método yield() que permite la
ejecución de otro thread con la misma prioridad. - Las prioridades viene definidas por variables
miembro de la clase Thread, que toman valores int
entre unos valores MAX_PRIORITY y MIN_PRIORITY
(entre 1 y 10), siendo la prioridad por defecto
NORM_PRIORITY(5).
18Planificación de Threads(IV).
- Cuando se crea un thread, hereda la prioridad
del thread que la ha creado. - Para modificar la prioridad de un thread se
utiliza el método setPriority(int), y para
obtener su valor el método int getPriority(). - El algoritmo de distribución de recursos en Java
- Es preemptive, es decir, el sistema ejecuta el
thread de mayor prioridad entre todos los que son
Runnable (excepcionalmente puede ejecutarse otro
thread para evitar que algunos procesos duerman
indefinidamente). - Si varios threads en estado Runnable tienen la
misma prioridad se van ejecutando sucesivamente
mediante permutación cíclica
19Planificación de Threads(V).
- Threads Daemon
- Los threads daemon llamodos servicios, se
ejecutan con prioridad baja y proporcionan un
servicio básico a un programa o programas cuando
la actividad de la máquina es reducida. - Un ejemplo de thread demonio que está
ejecutándose continuamente es el recolector de
basura (garbage collector). E - Un thread puede fijar su indicador de demonio
pasando un valor true al método setDaemon(). Si
se pasa false a este método, el thread será
devuelto por el sistema como un thread de
usuario. No obstante, esto último debe realizarse
antes de que se arranque el thread (start()).
20Control básico de threads.
- Finalización del la ejecución de un thread.
- Cuando un thread acaba su ejecución y es
finalizado , no puede volver a ser ejecutado. - Podemos detener un thread utilizando un flag que
utiliza un metodo run que debe terminar la
ejecución. - r.stopRunning() // r instancia de una clase que
implementa runnable
21Control básico de threads (II).
- Verificación del estado thread isAlived()
- boolean isAlived(). Devuelve true si el thread ha
sido inicializado con start y no ha terminado el
ciclo de ejecución. - Bloqueo de threads.
- sleep(). Permite detener un thread durante un
determinado tiempo - join(). Bloquea el thread actual, hasta que el
thead sobre el cual ha sido ejecutado el join
termina.
22Sincronización.
- Existen muchas situaciones interesantes donde
ejecutar threads concurrentes que compartan datos
y deban considerar el estado y actividad de otros
threads. Este conjunto de situaciones de
programación son conocidos como escenarios
'productor/consumidor' donde el productor genera
un canal de datos que es consumido por el
consumidor. Como los threads comparten un recurso
común, deben sincronizarse de alguna forma.
23Sincronización. Uso de synchronized
- Cada objeto tiene un flag de bloqueo
- La palabra clave synchronized permite controlar
el flag para activar accesos exclusivos al objeto
y cada objeto tendrá asociada una cola de espera. - Se pueden declarar bloques de código
synchronized. - synchronized ( variableCompartida )
-
- // acceso al recurso
-
- Métodos synchronized
- public synchronized void nomMetode ()
-
- // acceso al recurso
-
24Sincronización. Uso de synchronized
- El flag de bloqueo de un objeto se libera
- Cuando el thread termina el bloque de código
synchronized - Cuando le bloque de código synchronized lanza una
excepción. - Deadlock
- Dos threads esperando un flag de bloqueo
- No se detecta
- Se puede evitar
- Decidir el orden de obtención de los bloqueos
- Seguir con rigurosidad ese orden
- Liberar los bloqueos en orden inverso
25Sincronización. Comunicación entre threads
- wait() y notify()
- Si un thread ejecuta una llamada wait() sobre un
objeto x pausará su ejecución hasta que otro
thread ejecute la llamada a notify() mediante el
mismo objeto x. - Para poder ejecutar tanto un wait() como un
notify() el thread debera disponer del flag de
bloqueo, es decir, solo podrán ser ejecutadis
desde un bloque de codigo synchronized. - Listas de espera o pools
- Cuando un thread ejecuta wait() se libera el flag
de bloqueo y es colocado en la lista de espera o
pool del objeto (wait pool) - Al ejecutar notify() un thread abitrario es
movido de la lista de espera hacia una lista de
threads que esperan por el flag de bloqueo (lock
pool). notifyAll() despierta a todos los threads.
26Sincronización. Monitores
- Cuando un método synchronized se ejecuta adquiere
un monitor sobre el objeto. Cuando un thread
tiene el monitor del objeto ningún otro thread
podrá ejecutar un metodo synchronized. - Un thread sale del monitor cuando libera el flag
de bloqueo del objeto.
27Sincronización. Monitores(II).
- Un ejemplo típico del uso de monitores es el
esquema de productor/consumidor. - Aquí el productor y el consumidor son threads que
acceden a la región critica que es la tuberia o
buffer. Esta tiene que tener sus métodos
protegidos mediante synchronized y tiene que
hacer que los threads se comuniquen mediante
wait(), notify() y notifyAll().
28Bibliografia
- Dossier Programación Java (Tomo 2) PUE
- http//server2.ok.cl/java/Cap7/thread.html
- http//www.medicina.ull.es/aula/tutoriales/java/mo
nitors.html