Sei sulla pagina 1di 23

IES FRANCISCO AYALA GRANADA

MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

TEMA 2 PROGRAMACIN MULTIHILO


1. Programacin paralela o multihilo
1.1. Hilos de ejecucin de un proceso
1.2. Ventajas, y desventajas, de los hilos sobre los procesos

2. Hilos en JAVA
2.1.
2.2.
2.3.
2.4.
2.5.
2.6.

Clase Thread
Clases e interfaces relacionadas con los Hilos
Estados de ejecucin de un hilo
Mecanismos de control de hilos
Mecanismos de prioridad en los hilos
Sincronizacin de hilos

3. Otras herramientas multihilo de JAVA

Pgina 1 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

1. Programacin paralela o multihilo


Como vimos en el tema 1, la programacin paralela o multihilo es un tipo de
programacin concurrente basada en la ejecucin de varias tareas o hilos de ejecucin,
simultneamente. Est diseada para sistemas multiprocesador de memoria
compartida.

1.1. Hilos de ejecucin de un proceso


Un hilo es una caracterstica que permite a una aplicacin realizar varias tareas a la
vez, porque puede ser ejecutada en paralelo con otra tarea.
Un hilo (hebra, thread, subtarea, subproceso...) es una secuencia de cdigo en
ejecucin dentro de un proceso. Dentro de cada proceso puede haber varios hilos
ejecutndose. Por ejemplo, Word puede tener un hilo en background chequeando
automticamente la gramtica de lo que estoy escribiendo, mientras otro hilo puede
estar salvando automticamente los cambios del documento en el que estoy
trabajando.
Los distintos hilos de un proceso comparten una serie de recursos como el espacio
de memoria, los archivos abiertos, situacin de autenticacin, etc. El hecho de que los
hilos de ejecucin de un proceso compartan recursos, significa que cualquiera de ellos
puede modificar dichos recursos.
Un proceso sigue en ejecucin mientras al menos uno de sus hilos siga activo. Cuando
todos los hilos de un proceso acaban, el proceso finaliza y todos sus recursos son
liberados.

1.2. Ventajas, y desventajas de los hilos sobre los procesos


Si bien los hilos son generados a partir de la creacin de un proceso, podemos decir
que un proceso es un hilo de ejecucin, conocido como Monohilo. Pero las ventajas de
los hilos se dan cuando hablamos de Multihilos, que es cuando un proceso tiene
mltiples hilos de ejecucin los cuales realizan actividades distintas, que pueden o no
ser cooperativas entre s.
Las ventajas de los hilos sobre los procesos tienen que ver con el rendimiento pues
permiten ahorrar tiempo y espacio de memoria, as por ejemplo:
1. Se tarda menos tiempo en crear un hilo de una tarea existente, que en crear un
nuevo proceso.
2. Se tarda menos tiempo en terminar un hilo que en terminar un proceso.
3. Se tarda menos tiempo en cambiar entre dos hilos de una misma tarea que en
cambiar entre dos procesos.
4. Es ms sencillo la comunicacin (paso de mensajes por ejemplo) entre hilos de una
misma tarea que entre diferentes procesos.

Pgina 2 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

5. ...
Por otro lado, la utilizacin de hilos tiene sus desventajas:
1. No todos los lenguajes de programacin soportan multihilo
2. Hay que controlar los problemas relacionados con la comunicacin y sincronizacin
de hilos, cuando stos comparten recursos:
Inanicin: un hilo no puede utilizar los recursos porque otro no los libera.
Problemas de interbloqueo entre hilos (Deadlock), 2 hilos se bloquean
mutuamente esperndose el uno al otro sin avanzar ninguno de los 2.
Acceso a los recursos compartidos por 2 hilos, llamados recursos crticos.
Zonas de exclusin mutua, secciones crticas: trozo de cdigo donde solo se
ejecuta un hilo en un momento dado...
Condiciones de carrera: el resultado de la ejecucin de un proceso depende
del orden en que se ejecuten los hilos.
Errores de inconsistencia en la memoria compartida.

2. Hilos en JAVA
Java dispone de varios mecanismos para la programacin paralela. Por ejemplo la clase
Thread perteneciente a la API java.lang; y un conjunto de herramientas para
sincronizar hilos, clases... pertenecientes a la API java.util.concurrent. En este punto
nos vamos a centrar en la clase Thread.

2.1. Clase Thread


Java es un lenguaje de programacin orientado a objetos, concurrente, de propsito
general y multiplataforma creado por Sun Microsystems. Es un lenguaje de alto nivel
que permite trabajar en modo monohilo y en multihilo.
Java admite programacin multihilo (concurrente o paralela o multiproceso) gracias a
objetos Thread. Un objeto del tipo Thread es un hilo de ejecucin en un programa y
JAVA permite que una aplicacin tenga mltiples hilos de ejecucin o tareas
ejecutndose simultneamente.
En Java existen 2 tipos de thread: daemon thread (hilos demonio) y no daemon thread
(hilos no demonio). Los primeros son hilos del sistema y los segundos son hilos de
usuario.

2.2. Clases e interfaces relacionadas con los Hilos


El lenguaje de programacin Java proporciona soporte para hilos a travs de una
simple interfaz y un conjunto de clases que forman parte del paquete Java.lang y son
las siguientes:

Pgina 3 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

1.

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

Thread: La clase Thread es la clase que encapsula todo el control necesario para
implementar hilos de ejecucin. La clase Thread tiene sus mtodos descritos en:
http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html
de
los
cuales
destacamos los siguientes mtodos de clase (mtodos estticos que deben
llamarse de forma directa en la clase Thread):
a. currentThread(): devuelve el objeto Thread que representa al hilo que se
est ejecutando.
b. yield(): este mtodo hace que el sistema pase del hilo de ejecucin actual al
hilo siguiente disponible. As los hilos de menor prioridad no sufren
inanicin.
c. sleep(long): este mtodo pone a dormir el n de milisegundos indicado como
parmetro.
Entre los mtodos de instancia destacamos:
d. start(): inicializa el hilo, solo se puede llamar una vez
e. run(): Este mtodo contiene el cuerpo de ejecucin del hilo
f. setPriority(int): asigna al hilo la prioridad pasada como parmetro
g. getPriority(): devuelve la prioridad del hilo en ejecucin
h. setName(String): permite asignar un nombre al hilo
i. getName(): devuelve el nombre del hilo

2.

Runnable: Java no soporta herencia mltiple de forma directa, es decir, no se


puede derivar una clase de varias clases padre. Esto nos plantea la duda sobre
cmo podemos aadir la funcionalidad de Hilo a una clase que deriva de otra
clase, siendo sta distinta de Thread. Para lograr esto se utiliza la interfaz
Runnable que permite aadir la funcionalidad de un hilo a una clase simplemente
implementando la interfaz, en lugar de derivndola de la clase Thread. Esta
herramienta es muy til y a menudo es la nica salida que tenemos para
incorporar multihilo dentro de las clases. Su descripcin se encuentra en la web:
http://docs.oracle.com/javase/7/docs/api/java/lang/Runnable.html

3.

Object: La clase objeto est en la parte superior de la jerarqua de Java, es el padre


de todas las clases. esto significa que cada clase Java hereda la funcionalidad
proporcionada por la clase objeto. Aunque, no es una clase de apoyo a los hilos, la
clase objeto proporciona mtodos cruciales dentro de la arquitectura multihilo de
Java. Estos mtodos son wait, notify y notifyAll. Su descripcin se encuentra en la
web: http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

2.3. Estados de ejecucin de un hilo


El comportamiento de un hilo depende del estado en que se encuentre. Este estado
define su modo de operacin actual, por ejemplo, si se est ejecutando o no.
Podemos conocer el estado de un hilo con el mtodo de getState().

Pgina 4 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

Los estados en los que puede estar un hilo en Java son:


nuevo (New): Los hilos en estado new ya han sido creados y estn listos para
empezar a trabajar, pero an no han sido llamados para que empiecen a realizar
su trabajo. Un hilo est en el estado new a travs del mtodo homnimo.
Por Ejemplo: Thread t1 = new Thread(...)

Ejecutable (Runnable): Cuando se llama al mtodo start() inicializamos el hilo y


pasa al estado runnable (ejecutable).

En ejecucin (running) Solo estn ejecutndose los hilos inicializados que estn
utilizando la CPU. El sistema operativo selecciona de entre los hilos en estado
runnable, los que pasan al estado running y empieza a ejecutar el mtodo run().
Bloqueado (Not running): El estado not running se aplica a todos los hilos que
estn parados por alguna razn. Cuando un hilo est en este estado, no se le
asigna tiempo de CPU pero est listo para ser usado y es capaz de volver al estado
runnable en un momento dado. Los hilos pueden pasar al estado not running a
travs de varias vas, por ejemplo:
Si est dormido, porque se ha llamado al mtodo sleep()
Si est esperando, a travs del mtodo wait()
Cuando el subproceso est bloqueado en una operacin Entrada/Salida.

Dead: Un hilo entra en estado dead cuando finaliza su ejecucin.

2.4. Mecanismos de control de hilos


2.4.1. Creacin de Hilos
Un hilo en Java se crea como una instancia de la clase java.lang.Thread. Para definir e
instanciar un nuevo hilo, hay dos formas:
1. Extendiendo la clase Thread, esto es, creando una subclase de esta clase,
2. Implementando la interfaz Runnable.
Creacin de hilos extendiendo la clase Thread
En Java una hebra o hilo, es una clase por tanto la manera ms sencilla de crear una
hebra es crear una clase que herede de la clase Thread, la cual podramos instanciar
despus. Por ejemplo:
class MiHilo extends Thread {
public void run() {
...
}
}

// MiHilo Hereda la clase Thread


// redefine el mtodo run()

En este caso se pueden heredar los mtodos y variables de la clase padre. Pero, una
misma subclase solamente puede extender o derivar una vez de la clase padre Thread.

Pgina 5 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

Creacin de hilos Implementando la interfaz Runnable


Java no admite herencia mltiple, es decir una clase solo puede heredar o extender
una clase pero, puede implementar muchas interfaces. Runnable es un mecanismo
que permite esta posibilidad.
Si creamos hilos implementando la interfaz Runnable, se puede heredar una clase de
cualquier otra e implementar otras interfaces pero, sin perder el comportamiento de
la nuestra. Para crear un hilo con esta interfaz haramos as:
public class MiThread implements Runnable
{
Thread t;
public void run() {
// Ejecucin del thread una vez creado
...}
}
Creacin de objetos de la clase Thread
La creacin de objetos de la clase Thread se realiza a travs del mtodo new(), que
tiene varios constructores, entre ellos:
Thread();
Thread(objeto runnable);
Thread(objeto runnable, String nombre);
Thread(String nombre);
1. Para instanciar o crear un hilo, extendiendo de Thread, haramos as:
...
MiHilo h = new MiHilo();
...
2. Para instanciar o crear un hilo con la interfaz runnable haramos as:
...
MiThread h = new MiThread();
Thread t =new Treadh(h);
O lo que es lo mismo:
Thread t =new Treadh(new(MiThread(h));
2.4.2. Inicializacin de un hilo
En el punto anterior hemos visto como crear nuevos hilos. Cuando creamos hilos con
new(), stos estn en estado new. Para poder ejecutarlos hay que inicializarlos y as
pasarlos al estado runnable. La creacin e inicio de los hilos se hace dentro del mtodo
main().

Pgina 6 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

El inicio de los hilos se realiza con el mtodo start(). Este mtodo crea los recursos
necesarios para que el hilo pueda ejecutarse, lo incorpora a la lista de procesos
disponibles para ejecucin y llama al mtodo run(). Un hilo solo puede iniciarse una
vez, por tanto este mtodo no se puede llamar ms de una vez.
2.4.3. Ejecucin de un hilo
Una vez creado e inicializado un hilo, ste pasa del estado runnable al estado runnig
cuando el scheduler lo selecciona y ejecuta el mtodo run().
En el mtodo run se implementa el cdigo correspondiente a la accin o tarea que el
hilo debe desarrollar. Los hilos trabajan con el mtodo run() sin argumentos.
Cuando ejecutamos un programa con varios hilos de ejecucin podremos comprobar
que el comportamiento de los hilos no es predecible. Los hilos no necesariamente se
ejecutan en el mismo orden en que fueron introducidos. El scheduler controla el
tiempo de CPU de cada hilo y lo nico seguro es que cada hilo se ejecutar hasta
terminar su tarea. Si tenemos varios hilos en ejecucin y queremos saber cual se est
ejecutando en un momento dado, el mtodo Thread.currentThread.getName()
devuelve el nombre del hilo en ejecucin.
2.4.4. Suspensin o bloqueo de hilos
El S.O. asigna tiempos de CPU a los hilos inicializados con el mtodo start(). Pero a
veces es necesario detener temporalmente uno de ellos, cambiando su estado a
bloqueado, o not running. Para detener un hilo tenemos varias opciones:
i.

A travs del mtodo sleep(long), lleva al hilo a un estado de dormido, durante


un nmero de milisegundos concreto. El hilo vuelve al estado ejecutable cuando
pase el n de ms indicado. Si se necesita activar el proceso antes de que se agote
el periodo de inactividad, se puede utilizar el mtodo interrupt(). El mtodo
sleep() lanza la excepcin InterruptedException, por ello hay que incluirlo dentro
de un bloque try..catch .

ii.

A travs del mtodo wait() o wait(n ms) el hilo de ejecucin espere en estado
dormido hasta que se le notifique que contine. En wait() utilizaremos notify() o
notifyAll() para despertar el hilo. El mtodo notify informa a un hilo en espera de
que contine con su ejecucin. El mtodo notifyAll es similar a notify excepto
que se aplica a todos los hilos en espera. En wait (n ms) el hilo queda esperando
hasta que sea despertado a travs de notify o notifyAll o hasta el n de ms
indicado. Estos mtodos se suelen utilizar para codificar bloques de
sincronizacin o secciones crticas, donde es necsario sincronizar hilos que
necesitan acceder a un mismo recurso: dato, archivo, base de datos... por
ejemplo: el problema del productor-consumidor.

Pgina 7 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

iii.

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

Cuando el hilo est esperando operaciones de E/S. Al finalizar la operacin de


E/S el hilo recupera el estado ejecutable.

Este ejemplo muestra una aplicacin JAVA de creacin de hilos extendiendo la clase
Thread:
Ejemplo 1:
archivo Hilo1.java
public class Hilo1 extends Thread
{
private String nombre;
public Hilo1(String nombre)
{
this.nombre=nombre;
}
/** El mtodo run genera un n aleatorio de ms, que ser el tiempo que el hilo estar
dormido antes de visualizar su nombre y el retardo o tiempo que ha permanecido
dormido**/
public void run()
{
try{
int x=(int)(Math.random()*5000);
Thread.sleep(x);
System.out.println("Soy "+nombre+ " ("+x+")");
}
catch (Exception ex){
}
}
public static void main(String[] args)
{
Hilo1 t1 = new Hilo1("Pedro");
Hilo1 t2 = new Hilo1("Pablo");
Hilo1 t3 = new Hilo1("Juan");
t1.start();
//mtodo que inicializa el hilo y llama a run()
t2.start();
t3.start();
}
}
El siguiente ejemplo muestra una aplicacin JAVA creando hilos con Runnable:
Ejemplo 2:
archivo hilo2.java

Pgina 8 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

public class Hilo2 implements Runnable{


private String nombre;
public Hilo2(String nombre)
{
this.nombre=nombre;
}
public void run(){
try{
int x=(int)(Math.random()*5000);
Thread.sleep(x);
System.out.println("Soy "+nombre+ " ("+x+")");
}
catch (Exception ex){ }
}
public static void main(String[] args) {
Thread t1 = new Thread(new Hilo2("Pedro"));
Thread t2 = new Thread(new Hilo2("Pablo"));
Thread t3 = new Thread(new Hilo2("Juan"));
t1.start();
t2.start();
t3.start();
}
}
En este caso necesitamos crear una instancia de Thread antes de que el sistema pueda
ejecutar el proceso como un hilo.
La diferencia entre ambos mtodos de creacin de hilos en Java radica en la
flexibilidad con que cuenta el programador, que es mayor en el caso de la utilizacin
de la interfaz Runnable.
La mayora de las clases creadas que necesiten ejecutarse como un hilo implementarn
la interfaz Runnable, ya que as queda cubierta la posibilidad de que sean extendidas
por otras clases. Por ejemplo, si quisiera crear un applet con hilos de ejecucin:
public class miapplet extend Applet implements Runnable
Una vez declarada la clase que implementa la interface Runnable, ya puede ser
instanciada e iniciada como cualquier thread y cualquier subclase descendiente de esta
clase poseer tambin las caractersticas propias de los threads.
2.4.5.

Finalizacin de un hilo

En condiciones normales un hilo finaliza cuando terminan de ejecutarse todas las


instrucciones de su mtodo run(). Tambin se puede finalizar con el mtodo stop,
Pgina 9 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

siempre que no sea el de la clase Thread. Dicho mtodo se ha quedado obsoleto


porque genera estados de incoherencia en algunos objetos del programa, provocados
por un bloqueo o desbloqueo incorrecto de las instancias de los objetos. En su lugar
podemos crear un mtodo propio en un hilo del siguiente modo:
public void stopMe(){
stopMe()=null;
}
Un mtodo que nos permite comprobar si un hilo est vivo o no es la funcin
miembro isAlive(). Este mtodo devuelve un valor booleano.
Por ejemplo:
public static void main(String args[])
{
MiThread t = new MiThread();
System.out.println("isAlive() antes de iniciar: "+t.isAlive());
t.start();
System.out.println("isAlive() en ejecucin: "+t.isAlive());
}
La salida correspondiente al programa es:
isAlive() antes de iniciar el hilo: false
isAlive() en ejecucin: true
Devolver true en caso de que el hilo t1 haya iniciado su ejecucin. En otro caso,
devolver false.
Qu resultado devolvera esta funcin, si el hilo hubiese sido bloqueado o
dormido?
2.4.6.

Esperar a que finalice un hilo

A veces necesitamos esperar a que finalice un hilo o grupo de ellos para seguir
adelante con otras tareas, pero como los hilos se ejecutan concurrentemente con el
programa que los lanz, esto puede provocar salidas de programa no deseadas
relacionadas con el orden de ejecucin de las acciones programadas.
Si queremos que una accin se realice despus de finalizar un hilo hay que esperar a
que ste acabe, utilizando el mtodo join(). Este mtodo puede incluir como
parmetro el n de ms que queremos esperar a que acabe el hilo.
En el siguiente ejemplo, para que el mensaje de cada hilo se visualice en el mismo
orden que se introdujo, ser necesario llamar al mtodo join().
Ejemplo3:

Pgina 10 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

archivo Hilojoin.java
public class Hilojoin extends Thread
{
private String nombre;
public Hilojoin(String nombre)
{
this.nombre=nombre;
}
public void run(){
try{
int x=(int)(Math.random()*5000);
Thread.sleep(x);
System.out.println("Soy "+nombre+ " ("+x+")");
}
catch (Exception ex){
}
}
public static void main(String[] args) throws InterruptedException {
Hilojoin t1 = new Hilojoin("Pedro");
Hilojoin t2 = new Hilojoin("Pablo");
Hilojoin t3 = new Hilojoin("Juan");
t1.start();
t2.start();
t3.start();
t1.join();
t2.join();
t3.join();
System.out.println("fin del proceso");
}
}
Qu pasara si no utilizsemos el mtodo join?

2.5. Mecanismos de prioridad en los hilos


En los ordenadores que tienen una nica CPU, los hilos se ejecutan proporcionando la
ilusin de que lo hacen al mismo tiempo. Se puede modificar la prioridad de los hilos
despus de su creacin mediante setPriority(). A esta funcin se le pasa un entero
comprendido entre dos valores mnimo y mximo. Cuanto mayor sea el entero, mayor
ser la prioridad con la que se ejecuta el hilo.

Pgina 11 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

Cuando se crea un hilo en Java, ste hereda la prioridad de su padre, el hilo que lo ha
creado. A partir de aqu se le puede modificar su prioridad en cualquier momento
utilizando el mtodo setPriority.
La clase Thread define tres constantes que representan los niveles de prioridad
relativos para los subprocesos:
MIN_PRIORITY vale 1
MAX_PRIORITY vale 10
NORM_PRORITY
Tomando 1 el valor de la mnima prioridad y 10 el valor de la mxima prioridad.
Un ejemplo de hilo de baja prioridad es el que libera la memoria no usada que se
ejecuta en la Mquina Virtual Java. An cuando la liberacin de memoria es una tarea
muy importante, su baja prioridad evita que el procesador est ocupado demasiado
tiempo en ella, dejando a los procesos crticos el uso prioritario de la CPU. Pero si en
un momento dado la memoria se agotara, los subprocesos crticos entran en estado de
espera, dejando a la CPU que ejecute el subproceso que libera la memoria no usada (el
de menos prioridad).
Para saber el nivel del prioridad de un subproceso se usa la funcin getPriority():
int prioridad=hilo1.getPriority();
Se puede cambiar la prioridad de un subproceso respecto de otro aumentando o
disminuyendo su valor de prioridad, por ejemplo:
hilo2.setPriority(hilo1.getPriority()+1);
Se ejecutar primero el hilo de prioridad superior, y cuando ste finaliza o se convierte
en No Ejecutable, comienza la ejecucin de un hilo de prioridad inferior. El hilo
seleccionado se ejecutar hasta que:
1. Un hilo con prioridad mayor pase a ser Ejecutable.
2. Abandone, o termine su mtodo run.
Los sistemas operativos no estn obligados a tener en cuenta la prioridad de los hilos.
Cuando todos los hilos tienen la misma prioridad, y queremos que la CPU cambie de
hilo de forma equilibrada, se utiliza el mtodo yield(). Este mtodo indica a la JVM
(mquina virtual de java) que el hilo en ejecucin puede pasar del estado running a
runnable, permitiendo as que otros hilos se ejecuten.
Para probar la prioridad en hilos, vamos a partir del siguiente archivo:
Ejemplo 4:
archivo hilo.java
public class hilo extends Thread
{
Pgina 12 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

public hilo(String nombre) {


super(nombre);
}
@Override
public void run(){
for(int i=1; i<10; i++){
System.out.println(getName()+": "+i);
try{
sleep(100);
}catch(InterruptedException ex){}
}
}
public static void main(String[] args) {
hilo hilo1=new hilo("HOLA LUNA!!...");
hilo hilo2=new hilo("HOLA SOL!!!...");
hilo1.start();
hilo2.start();
}
}
Ahora vamos a intentar lo siguiente:
1.
2.
3.
4.
5.
6.

Lo ejecutamos sin asignar prioridad


Lo ejecutamos asignando mas prioridad a la luna
Lo ejecutamos asignando mas prioridad al sol
Lo ejecutamos asignando la mnima prioridad a uno de los 2
Obtienes los resultados esperados?
Qu debemos hacer para que el mensaje que muestra la prioridad del hilo se
visualice al final del programa?

2.6. Sincronizacin de varios hilos de ejecucin


2.6.1. Monitores
El problema de la sincronizacin de hilos tiene lugar cuando varios hilos intentan
acceder a los mismos recursos. Por ejemplo: un marido y una mujer intentan sacar
dinero a la vez de su cuenta en distintos cajeros, Qu pasara si quisieran sacar 100
cada uno y su saldo fuese de 150?.
El acceso a los recursos compartidos (recursos crticos), debe ser monitoreado. El
fragmento de cdigo que manipula esos recursos se llama seccin crtica o zona de
exclusin mutua. Es un trozo de cdigo, en el que la correccin del programa se ve
comprometido por el uso de variables compartidas. Un hilo slo podr acceder a esta
seccin crtica durante un tiempo determinado para que no haya inanicin.

Pgina 13 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

La seccin crtica debe ser mutuamente excluyente, es decir, si un hilo est ejecutando
su seccin crtica en un momento dado, ningn otro hilo puede ejecutarla hasta que
no finalice el que est usndola.
Java dispone del modificador synchronized que, aplicado a un mtodo, garantiza que
ste se ejecuta de forma excluyente. Una clase con un mtodo synchronized() se llama
monitor, (tubera, buffer) porque dentro de ste se estar monitoreando algn recurso
crtico. Un monitor implementa una seccin crtica. Para que una clase sea monitor,
todos sus mtodos de la clase deben ser synchronized.
Para codificar monitores en Java, utilizamos, adems de synchronized, los mtodos:
1. wait(): Si no se cumple la condicin, esperamos.
2. notify(): Cuando hemos entrado en la seccin crtica, y finalizamos la tarea
asignada, avisamos al hilo que haya esperando que puede entrar, si se cumple
la condicin.
3. notifyAll(): Igual que el anterior, pero notificamos a todos los hilos que hay
esperando.
Por ejemplo, si queremos que la variable c de este programa sea manipulada
correctamente, en Java habra que codificarlo as:
public class SynchronizedCounter {
private int c = 0;
public synchronized void increment() {
c++;
}
public synchronized void decrement() {
c--;
}
public synchronized int value() {
return c;
}
}
Java permite sincronizar una parte del cdigo de un mtodo. Para ello se utiliza la
palabra clave syncronized(objeto), indicando entre parntesis el objeto que se desea
sincronizar. Por ejemplo si se desea sincronizar el propio thread en una parte del
mtodo run(), el cdigo podra ser:
public void run() {
while(true) {
...
syncronized(this) { // El objeto a sincronizar es el propio thread

Pgina 14 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

... // Cdigo sincronizado


}
...
...
Resto de instrucciones accesibles, porque no estn sincronizadas
}
}
2.6.2.

Problema del productor consumidor

El Productor/Consumidor, es conocido como problema del buffer limitado. Dos


procesos comparten un almacn(buffer) de tamao fijo. Uno de ellos, el productor,
coloca informacin en el almacn (buffer) mientras que el otro, el consumidor, la
obtiene de l. Si el productor desea colocar un nuevo elemento, y el almacn se
encuentra lleno, este deber irse a \dormir". El consumidor despertar al productor
cuando elimine un elemento del almacn. De forma anloga, si el almacn esta vacio y
el consumidor desea extraer un elemento del almacn, este debe \dormirse" hasta
que el productor coloque algo en el almacn.
Para codificar este problema contaremos con 2 hilos: el productor que genera
elementos y los guarda y el consumidor que los extrae. Pueden darse muchas
situaciones:
los 2 quieren acceder a la vez al almacn,
el productor genera a distinta velocidad que el consumidor,
el productor ha llenado su reserva y no puede producir ms hasta que el
consumidor no saque algo,
el consumidor no puede acceder porque el almacn est vacio...
Por tanto, debe establecerse un mecanismo que controle el acceso de ambos al
almacn (sincronizacin de tareas). Vamos a ver dos formas de implementar este
problema: la primera sin monitor y la segunda utilizando un monitor.
Productor-consumidor sin monitor
(Proyecto: sincronizapuntes)
En este ejemplo el productor genera un entero entre 0 y 9 (inclusive), lo almacena en
un objeto "CubbyHole", e imprime el nmero generado, respetando el orden de
introduccin. Adems, el productor duerme durante un tiempo antes de repetir el ciclo
de generacin de nmeros.
class Productor extends Thread {
private CubbyHole cubbyhole;
private int numero;
public Productor(CubbyHole c, int numero) {

Pgina 15 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

cubbyhole = c;
this.numero = numero; // retardo aplicado al productor
}
public void run() {
for (int i = 0; i < 10; i++) {
cubbyhole.put(i);
System.out.println("Productor pone: " +i);
try {
sleep(numero);
} catch (InterruptedException e) {}
}
}
El consumidor, por su parte, est hambriento, consume los enteros de CubbyHole
una vez y en el mismo orden que fueron introducidos, tan pronto como estn
disponibles.
class Consumidor extends Thread {
private CubbyHole cubbyhole;
private int numero;
public Consumidor(CubbyHole c, int numero) {
cubbyhole = c;
this.numero = numero;
}
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = cubbyhole.get();
System.out.println("Consumidor saca:"+value);
try {
sleep(numero);
} catch (InterruptedException e) {}
}
CubbyHole es la clase que se encarga de poner y extraer los datos del productor y
consumidor
class CubbyHole {
private int contents;
public int get() {
return contents;
}

Pgina 16 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

public void put(int value) {


contents = value;
}
La clase que utiliza los objetos de las clases creadas: Productor, Consumidor y
Cubbyhole, sera la siguiente:
public class TestMonitor {
public static void main(String[] args) {
CubbyHole b=new CubbyHole();
Productor p=new Productor(b,1000);
Consumidor c=new Consumidor(b,2000);
p.start();
c.start();
}
}
En este ejemplo, el Productor y el Consumidor comparten datos a travs de un objeto
CubbyHole comn. Ninguno de los dos controla que el consumidor obtiene cada valor
producido una vez. La sincronizacin entre estos dos hilos ocurre a un nivel inferior,
dentro de los mtodos get() y put() del objeto CubbyHole. Sin embargo, si estos dos
hilos no estn sincronizados, los problemas que podra provocar esta situacin son:
1. El Productor es ms rpido que el Consumidor y generara dos nmeros antes
de que el Consumidor tuviera una posibilidad de consumir el primer nmero.
As el Consumidor se saltara un nmero. Parte de la salida se podra parecer a
esto:
Consumidor #1 obtiene: 3
Productor #1 pone: 4
Productor #1 pone: 5
Consumidor #1 obtiene: 5
2. El Consumidor es ms rpido que el productor y consumiera el mismo valor dos
o ms veces. En esta situacin el Consumidor imprimir el mismo valor dos
veces y podra producir una salida como sta.
Productor #1 pone: 4
Consumidor #1 obtiene: 4
Consumidor #1 obtiene: 4
Productor #1 pone: 5
De cualquier forma, el resultado es errneo, porque lo que se quiere es que el
consumidor obtenga cada entero producido por el productor slo una vez. Los
problemas anteriores, se llaman condiciones de carrera. Suceden cuando varios

Pgina 17 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

hilos ejecutados asncronamente intentan acceder a un mismo objeto al mismo tiempo


y obtienen resultados errneos.
Para prevenir las condiciones de carrera, el almacenamiento de un nuevo entero en
CubbyHole por el Productor debe estar sincronizado con la recuperacin del entero
por parte del Consumidor. El Consumidor debe consumir cada entero exactamente
una vez.
Productor consumidor con Monitor
A los objetos como CubbyHole, a los que acceden varios hilos, son llamados
condiciones variables o "recursos crticos". Una de las formas de controlar el acceso
a estas condiciones variables o recursos crticos, y por tanto de sincronizar los hilos,
son los monitores. Los monitores implementan las secciones crticas que son los
segmentos del cdigo donde los hilos concurrentes acceden a los recursos crticos.
Estas secciones, se marcan con la palabra reservada synchronized.
Java asocia un solo monitor a cada objeto que tiene un mtodo sincronizado. El
ejemplo del productor-consumidor tiene dos mtodos de sincronizacin: put(), que
cambia el valor de CubbyHole, y get(), para recuperar el valor actual. Ahora CubbyHole
es un monitor o clase sincronizada encargada, de poner y extraer los datos del
productor y consumidor. Este sera el cdigo fuente del objeto CubbyHole
sincronizado.
class CubbyHole {
private int contents;
private boolean available = false;
public synchronized int get() {
while (available == false) {
try {
wait();
} catch (InterruptedException e) {}
}
available = false;
notify();
return contents;
}
public synchronized void put(int value) {
while (available == true) {
try {
wait();
} catch (InterruptedException e) {}
}

Pgina 18 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

contents = value;
available = true;
notify();
}
}
Qu sucedera si estos mtodos no estuviesen sealados como seccin crtica?
Prueba este ejemplo , con el productor durmiendo, con el consumidor durmiendo,
estando los 2 durmiendo, estando los dos despiertos... y con el monitor sin
sincronizar. Observa lo que pasa con wait y notify cuando el monitor no est
sincronizado.
Cuando el Productor invoca el mtodo put(), adquiere el monitor del objeto CubbyHole
y por lo tanto el Consumidor no podr llamar a get() y se quedar bloqueado. Lo
mismo sucede cuando el Consumidor invoca a get().
public synchronized void put(int value) // El productor adquiere el monitor
{
while (available == true) {
try {
wait(); // espera que el consumidor invoque a notify
} catch (InterruptedException e) {}
}
contents = value;
available = true;
notify();
// el productor libera el monitor
}
public synchronized int get() // El consumidor adquiere el monitor
{
while (available == false) {
try {
wait();
// espera que el Productor invoque a notify
} catch (InterruptedException e) {}
}
available = false;
notify();
// el Consumidor libera el monitor
return contents;
}
}
La variable contents tiene el valor actual de CubbyHole y available indica si se puede
recuperar o no el valor. Cuando available es verdadero, el productor an no ha
acabado de producir.
Pgina 19 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

CubbyHole tiene dos mtodos de sincronizacin, y Java proporciona un solo monitor


para cada ejemplar de CubbyHole. Siempre que el control entra en un mtodo
sincronizado, el hilo que ha llamado al mtodo, adquiere el monitor del objeto al cual
pertenece el mtodo. Otros hilos no pueden llamar a un mtodo sincronizado del
mismo objeto mientras el monitor no sea liberado.
Existen otros mecanismos para resolver el problema del productor consumidor
diferentes al uso de monitores: semforos, cerrojos, colas sincronizadas...
2.6.3.

Otros problemas clsicos de sincronizacin

Adems del problema del productor-consumidor, existen otros problemas clsicos de


concurrencia:
1. El del fumador de cigarros, Considere un sistema con tres procesos fumadores y
un proceso agente. Cada fumador est continuamente enrollando y fumando
cigarrillos. Sin embargo, para enrollar y fumar un cigarrillo, el fumador necesita tres
ingredientes: tabaco, papel, y fsforos. Uno de los procesos fumadores tiene papel,
otro tiene el tabaco y el tercero los fsforos. El agente tiene una cantidad infinita
de los tres materiales. El agente coloca dos de los ingredientes sobre la mesa. El
fumador que tiene el ingrediente restante enrolla un cigarrillo y se lo fuma,
avisando al agente cuando termina. Entonces, el agente coloca dos de los tres
ingredientes y se repite el ciclo.
2. La panadera de Lamport, en este problema una panadera tiene una variedad de
panes y pasteles vendidos por n vendedores. Cada uno de los cuales toma un
nmero al entrar. El cliente espera hasta or su nmero. Cuando el vendedor se
desocupa, llama al siguiente numero.
3. Los filsofos que cenan (sabios), Hay cinco filsofos chinos que se pasan sus vidas
pensando y comiendo. Comparten una mesa circular, alrededor de la cual se
sientan. En su centro se encuentra con una provisin infinita de arroz, y sobre ella
hay cinco palitos, uno de cada lado de los filsofos. Cuando un filsofo piensa, no
interacta con sus colegas. De vez en cuando, un filsofo tiene hambre y trata de
levantar los dos palitos ms cercanos a l. Un filosofo puede levantar un palito a la
vez, y no puede tomar un palito que ya est en la mano de un vecino. Cuando un
filsofo tiene ambos palitos, puede comer. Cuando termino de hacerlo, deja sus
dos palitos y comienza a pensar de nuevo.
4. El barbero dormiln, Una peluquera tiene un barbero, una silla de peluquero y n
sillas para que se sienten los clientes en espera, si es que los hay. Si no hay clientes
presentes, el barbero se sienta en su silla de peluquero y se duerme. Cuando llega
un cliente, este debe despertar al barbero dormiln. Si llegan ms clientes mientras
el barbero corta el cabello de un cliente, estos deben esperar sentados (si hay sillas

Pgina 20 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

desocupadas) o salirse de la peluquera (si todas las sillas estn ocupadas). El


problema consiste en programar al barbero y los clientes sin entrar en condicin
de competencia.
5. Lectores y escritores, imaginemos una enorme base de datos, como por ejemplo
un sistema de reservaciones de en una lnea area, con muchos procesos en
competencia, que intentan leer y escribir en ella. Se puede aceptar que varios
procesos lean la base de datos al mismo tiempo, pero si uno de los procesos est
escribiendo, (es decir modificando) la base de datos, ninguno de los dems
procesos deber tener acceso a esta, ni siquiera los lectores. El problema es como
programar a los lectores y escritores.

3. Otras herramientas multihilo de JAVA


Java dispone de ms herramientas para sincronizar hilos, y para trabajar con la
programacin paralela. La mayora de ellas se encuentran en la API
java.util.concurrent. Todo lo relacionado con la programacin paralela o multihilo
est descrito en el tutorial de JAVA sobre concurrencia en la web:
http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html
Veamos brevemente algunas de ellas:
1. Semaphore (Semforos): Los semforos garantizan la exclusin mutua y la
sincronizacin de hilos. Al entrar en una zona critica un hilo adquiere el
derecho de acceso y al salir lo libera.En Java para codificar semforos
utilizamos los mtodos:
acquire(): Para adquirir el semforo, cuando se ha entrado en zona crtica.
release(): Al salir de la zona crtica, porque hemos terminado.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Semaphore.ht
ml
2. Locks (cerrojos): es un mecanismo de sincronizacin utilizado para delimitar
zonas de exclusin mutua. Utiliza los mtodos locks y unlocks para marcar el
inicio
y
el
fin
de
la
zona
de
exclusin
mutua.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/locks/packagesummary.html
3. Variables Atmicas: son variables de diferentes tipos (booleano, entero, largo,
array de enteros...) en las que todos sus mtodos estn sincronizados.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/packag
e-summary.html
4. Colas sincronizadas:

Pgina 21 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/SynchronousQ
ueue.html
5. CountDownLatch, CyclicBarrier, Exchanger y Phaser: son clases sincronizadas.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Exchanger.html
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Phaser.html...
6. Callable: interfaz similar a Runnable, cuando necesitamos devolver un
resultado o lanzar una excepcion. Se utiliza con Executors y Future.
7. Executor: es una interfaz con mltiples implementaciones que permiten
controlar la ejecucin de un hilo, por ejemplo, podemos limitar el nmero de
hilos que deseamos se ejecuten concurrentemente.
8. Future: interfaz utilizado con Executor para devolver el resultado de un hilo
callable diseado para evitar problema de inconsistencia de datos en la
memoria.
9. ThreadGroup: es una forma de agrupar varios hilos bajo un nombre comn.
Pertenece a java.lang.
10. Thread factory: es una forma de implementar una fbrica de objetos hilo
Estos se describen en: http://docs.oracle.com/javase/7/docs/api/
11. Fork-join: es una implementacin de la interfaz Executor que resuelve las
tareas dividindolas en ms pequeas, de forma recursiva.
http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ForkJoinWorke
rThread.html
12. ...

EJERCICIOS OBLIGATORIOS
1. Relacin 2
2. Relacin 3

EJERCICIOS OPCIONALES
1. Implementa el ejemplo del productor consumidor con otra herramienta de
sincronizacin de Java distinta a los monitores. Crea un documento pdf con la
informacin recopilada y el archivo fuente depurado y documentado. Enva el
documento por correo electrnico antes del 31 de Octubre.
2. Investiga sobre otros problemas de concurrencia, descrbelos e intenta
codificar en Java alguno de ellos. Crea un documento pdf con la informacin
recopilada y el archivo fuente depurado y documentado. Enva el documento
por correo electrnico antes del 31 de Octubre.
Pgina 22 de 23

IES FRANCISCO AYALA GRANADA


MDULO: PSP

CURSO 2013-2014
TEMA 2

GRUPO: 2 DAM
PROGRAMACIN MULTIHILO

3. Investiga sobre alguna de las herramientas multihilo, no utilizadas hasta ahora


en los ejercicios anteriores. Descrbela e intenta codificar en Java alguna
aplicacin que la utilice. Crea un documento pdf con la informacin recopilada
incluyendo el archivo fuente depurado y documentado. Enva el documento
por correo electrnico antes del 31 de Octubre.

Webgrafa:
1. http://www.youtube.com/watch?v=vS2Mg7Vxwn0, videotutorial de Jess Conde
sobre Threads en JAVA.
2. http://www.oracle.com/technetwork/java/javase/downloads/index.html descarga de
JDK y Netbeans ltima versin.
web en ingls con
3. http://www.isr.umd.edu/~austin/ence489c.d/threads.html
ejemplos de hilos: sincronizacin, animacin, reloj...
4. http://www.sc.ehu.es/sbweb/fisica/cursoJava/applets/threads/threads.htm
web
similar con ejemplos de hilos similares a los de la web anterior.
5. http://arquimedes.matem.unam.mx/pasados/java_profundizacion/Unidad06.htm
ejemplos de aplicaciones de los hilos: applet, animaciones..

Pgina 23 de 23

Potrebbero piacerti anche