Programación Concurrente en Java

Slides:



Advertisements
Presentaciones similares
FUNDAMENTALS OF THE JAVA PROGRAMMING LANGUAGE
Advertisements

Introducción a C++ Sistemas Operativos
JAVA PERSISTENCE API (JPA) - Relaciones
CJ02 – Técnicas avanzadas en java 1.4 y 5.0
FUNDAMENTALS OF THE JAVA PROGRAMMING LANGUAGE (SL-110) CAPÍTULO 8: ESTRUCTURAS DE REPETICIÓN Ing. Ronald Criollo.
Programación Interactiva Hilos
generic constraint development environment
Ejemplo de Programa C++
Ejemplo de Hilos. public class RelojApplet extends Applet implements Runnable { Hereda applet y la clase Thread ( simula la herencia múltiple.
Algoritmo y Estructura de Datos I I Facultad de Ingeniería y Arquitectura Ing. Juan José Montero Román. Sesión 13 - Programación.
Un constructor es un método que inicia un objeto inmediatamente después de su creación. De esta forma nos evitamos el tener que iniciar las variables.
UML Lenguaje Unificado de Construcción de Modelos
Programación II Listas
Defina una clase TempMinEstacion que encapsule la representación de las temperaturas mínimas registradas en una estación meteorológica en un período y.
Tipos de Datos Abstractos Vector de Racionales
Defina una clase TempMinMaxEst que encapsule la representación de las temperaturas mínimas y máximas registradas en una estación meteorológica y brinde.
Inner classes CAPITULO 8.
Consideraciones. Un Bean public class AddressBean { //properties private String street; private String city; private String state; private String zip;
INFORMATICA I Funciones CLASE 13.
1 Entrada/Salida en Java Jaime Ramírez, Ángel Lucas González DLSIIS. Facultad de Informática Universidad Politécnica de Madrid.
Tema 4 Árboles. Árbol sobre matriz.
SOBRECARGA DE FUNCIONES
Estructuras de Datos Manipulación de la Especificación de la Lista en C++
Estructuras de Datos Cont. C++ y Tipos de Datos. Ejemplo: Vector de Objetos #include class estudiante { private: int aCarne; char aNombre[20]; float aNota;
Programación II Colas Igor Santos Grueiro.
Genericidad Una clase genérica encapsula una estructura y brinda un conjunto de servicios cuya implementación no depende del tipo de las componentes.
Lenguajes de Programación Tema 4. Paradigma Orientado a Objetos Java 1.5 Pedro García López
Introducción Program Slicing Pattern Matching Problema: Pérdida de precisión Solución Conclusiones Peculiaridades de Erlang Erlang Dependence Graph.
Ejercicios de Arreglos y Funciones “En C” Semestre de Otoño 2006 Claudio Gutiérrez-Soto.
FUNCIONES EN C.
Java. Threads (Hebras) Los sistemas operativos actuales permiten la multitarea, aunque esta se de tiempo compartido cuando se trabaja con un solo procesador.
Middleware Java 2 Enterprise Edition
RMI JAVA Implementación.
Estructuras de Datos y Algoritmos TDA LISTA. Metáfora del TDA (repaso) Conjunto de operaciones forman una pared forman una interfase entre los programas.
Clases abstractas no polimórficas para C++ Universidad de Costa Rica Escuela de Ciencias de la Computación e Informática Agenda.
Igor Santos Grueiro. De este tipo de pilas NO vamos a hablar.
TEMA 1 PROGRAMACIÓN MODULAR.
FUNCIONES EN C.
Semáforos Cecilia Hernández
Algoritmos para Ordenar datos
Capítulo 5 - b: Hilos. 4.2 Silberschatz, Galvin and Gagne ©2005 Operating System Concepts – 7 th edition, Jan 23, 2005 Ejemplo de hilos: un applet Un.
PROGRAMACIÓN ORIENTADA A OBJETOS USANDO C++
INFORMATICA III ESCUELA DE INGENIERIA ELECTRONICA DEPARTAMENTO DE SISTEMAS E INFORMATICA.
INFORMATICA III ESCUELA DE INGENIERIA ELECTRONICA DEPARTAMENTO DE SISTEMAS E INFORMATICA.
TEMA 2. Programación Concurrente
Algoritmos y programación 3 - cátedra Fontela Concurrencia.
/** * Write a description of class General here. */ public class General { // instance variables - replace the example below with your own private int.
Listas. Utilización de un TAD Lista. Interfaz del TAD LISTA public interface Lista { void crearNodo (); /*Crea un nuevo nodo en el TadLista*/ int devolverClave.
Tema 1: Concurrencia con Java
SERIES Y SUMATORIAS.
Programación Avanzada
EL MUNDO DE LOS OBJETOS PROGRAMANDO EN JAVA.
Ingeniero en Computación José Alfredo Cobián Campos
IPOO 2 cuatrimestre 2017 Departamento de Ciencias e Ingeniería
Funciones y Clases Amigas (Friend)‏ Miembros Estáticos (Static)
Funciones y Clases Amigas (Friend)‏ Miembros Estáticos (Static)
INTRODUCCIÓN A LA PROGRAMACIÓN ORIENTADA A OBJETOS
Monitores Mecanismo sincronización de nivel más alto que semáforos Construcción a nivel de lenguaje de programación que controla el acceso a datos compartidos.
Funciones y Clases Amigas (Friend)‏ Miembros Estáticos (Static)
Programación Avanzada
Fundamentos del lenguaje de programación Condicionales, ciclos, Métodos, enumeraciones Escuela Técnica Superior Kinal Instructor Edwin Tumax.
Herencia en C#.
Funciones y Clases Amigas (Friend)‏ Miembros Estáticos (Static)
Objetos con linea de ejecucion propia
IPOO 2 cuatrimestre 2018 Departamento de Ciencias e Ingeniería
Funciones y Clases Amigas (Friend)‏ Miembros Estáticos (Static)
Funciones y Clases Amigas (Friend)‏ Miembros Estáticos (Static)
Programación Orientada a Objetos
SISTEMAS OPERATIVOS JOSE ANGEL MORENO B. Ingeniero de Sistemas TP # Copnia Universidad Incca de Colombia CORPORACI Ó N UNIVERSITARIA REMINGTON.
Transcripción de la presentación:

Programación Concurrente en Java Métodos sincronizados Monitores y condiciones Programación Concurrente ETSI Informática-UMA M.M. Gallardo

Métodos Sincronizados Cada objeto Java tiene asociado un lock (cerrojo). La palabra synchronized puede utilizarse para señalar aquellos métodos del objeto que deben ejecutarse en exclusión mutua. Antes de ejecutar un método sincronizado hay que competir para conseguir el lock del objeto al que pertenece.

Ejemplo: Problema de los jardines public class Cont { private int c = 0; public synchronized void inc(int i){ c++; } public synchronized int valor(){ return c; La ejecución de inc se realiza en exclusión mutua

Ejemplo: Problema de los jardines public class puerta implements Runnable{ Cont c; public jardin(Cont c){this.c = c;} public void run(){ for (int i = 0; i<20; i++) c.inc(1); } La ejecución de inc se realiza en exclusión mutua

Ejemplo: Problema de los jardines public class UsaJardines { public static void main(String[] args){ final int N = 10; Cont c = new Cont(); puerta[] p = new puerta[N]; for (int i = 0; i< N; i++) p[i] = new puerta(c); Thread[] ph = new Thread[N]; for (int i = 0; i< N; i++) ph[i] = new Thread(p[i]); for (int i = 0; i< N; i++) ph[i].start(); for (int i = 0; i< N; i++) try{ph[i].join(); }catch (InterruptedException e){} System.out.println(c.valor()); } Todas las hebras compiten

Mecanismo de entrada/salida al Monitor

Java no asigna ninguna estructura concreta a las hebras que están en el conjunto de entrada. La implementación podría usar Una FIFO Una LIFO Una FIFO basada en prioridades

Condiciones de sincronización Cuando una hebra que tiene el lock de un objeto y debe suspenderse debido a alguna condición de sincronización, se introduce en el conjunto de espera del objeto, llamando al método void wait() Cuando una hebra ejecuta wait(): - Libera el lock del objeto sincronizado - Se bloquea en el conjunto de espera

Mecanismo de entrada/salida revisado

Disciplina del Monitor Los métodos void notify(), void notifiyAll() despiertan a una/todas las hebras del conjunto de espera. Java utiliza la disciplina notify-and-continue, es decir, la hebra que hace notify continúa con el lock del monitor. Por lo tanto, la hebra que espera debe ejecutar un código del tipo: while (!condicion) try {wait(); } catch (Exception e){}

Métodos sincronizados: Productor/Consumidor public class Buffer { private int[] b; private int tam; private int i=0; private int j=0; private int numDatos = 0; public Buffer(int t){ tam = t; b = new int[tam]; } ...........

Métodos sincronizados: Productor/Consumidor ..... public synchronized void poner(int d) throws InterruptedException{ while (numDatos == tam) wait(); b[i] = d; i = (i + 1) % tam; numDatos++; notify(); } public synchronized int extraer() throws InterruptedException{ while (numDatos == 0) wait(); int aux = j; j = (j + 1) % tam; numDatos--; return b[aux]; mientras el buffer está lleno/vacío esperar

Métodos sincronizados: Productor/Consumidor ..... public synchronized void poner(int d) throws InterruptedException{ while (numDatos == tam) wait(); b[i] = d; i = (i + 1) % tam; numDatos++; notify(); } public synchronized int extraer() throws InterruptedException{ while (numDatos == 0) wait(); int aux = j; j = (j + 1) % tam; numDatos--; return b[aux]; Cambia el estado del buffer y aviso a la otra hebra, por si acaso

Métodos sincronizados: conjunto de espera único Cuando se utilizan métodos sincronizados hay sólo un conjunto de espera, en el que pueden estar suspendidas hebras que esperan que diferentes condiciones de sincronización sean ciertas. Cuando una hebra ejecuta notify, puede ser que no despierte a la hebra adecuada, por lo que habrá que programar un despertado en cascada o utilizar el método notifyAll().

Múltiples productores y consumidores Condiciones de sincronización Hay varios procesos productores y consumidores. Todos los procesos utilizan el buffer en exclusión mutua. Un productor no puede escribir hasta que no hay sitio en el buffer. Los consumidores leen todos los datos producidos, En el mismo orden. Si el buffer está vacío esperan.

Múltiples productores y consumidores -suponiendo 1 productor y 3 consumidores j numDatos = 3 b f k M Z A 1 2 3 flect c 2 3 5 Índice para cada consumidor

Múltiples productores y consumidores -si el consumidor 2 consume numDatos = 3 j b f k M Z A 1 2 3 flect fcons c 2 3 4 3 2 Índice para cada consumidor Ya no puede consumir más

Múltiples productores y consumidores -si el consumidor 0 consume numDatos = 2 j b f k M Z A 2 3 flect fcons c 3 3 4 2 2 Índice para cada consumidor Deja un hueco libre para el productor

Múltiples productores y consumidores -si el productor produce numDatos = 3 j b f k M Z A H 2 3 flect 3 fcons c 3 3 4 3 3 1 Índice para cada consumidor Indica a todos que pueden Consumir un dato más

Múltiples productores y consumidores package multProdCons; public class Buffer { private int[] b; // buffer private int[] c; // indice de cada consumidor private int[] fdatos; // para cada consumidor, los datos que le quedan por leer private int[] flect; // para cada dato, las lecturas que le quedan private int tam; private int i=0; private int j=0; private int numDatos = 0; private int nlectores = 0; ................. }

Múltiples productores y consumidores public Buffer(int t,int nlectores){ tam = t; b = new int[tam]; c = new int[tam]; for (int i=0;i<tam;i++) c[i] = 0; this.nlectores = nlectores; fdatos = new int[nlectores]; for (int i=0;i<nlectores;i++) fdatos[i] = 0; flect = new int[tam]; for (int i = 0; i < tam ; i++) flect[i] = 0; System.out.println("buffer inicializado"); }

Múltiples productores y consumidores public synchronized void poner(int id,int d) throws InterruptedException{ while (numDatos == tam) {notify(); wait();} b[i] = d; for (int c = 0; c < nlectores ; c++) fdatos[c]++; flect[i] = nlectores; i = (i + 1) % tam; numDatos++; notify(); } En la sala de espera hay procesos productores y consumidores. Cuando se despierta una hebra, puede ser que tenga que seguir esperando.... Desperado en cascada

Múltiples productores y consumidores public synchronized int extraer(int id) throws InterruptedException{ while (fdatos[id] == 0) {notify(); wait();} int aux = c[id]; fdatos[id]--; flect[c[id]]--; if (flect[c[id]] == 0) {numDatos--; notify();} c[id] = (c[id] + 1) % tam; return b[aux]; } Como en el caso de los productores Desperado en cascada

Múltiples productores y consumidores public class Consumidor implements Runnable{ Buffer b; int id; public Consumidor(Buffer b, int id){ this.b = b; this.id = id; } public void run(){ int d = 0; System.out.println("comienza consumidor"); for (int i=0;i<10;i++){ try{d = b.extraer(id); } catch (Exception e){}; System.out.println("Consumidor " + d);

Múltiples productores y consumidores public class Productor implements Runnable{ Buffer b; int id; public Productor(Buffer b,int id){ this.b = b; this.id = id; } public void run(){ System.out.println("comienza productor"); for (int i = 0; i<10; i++){ try {b.poner(id,i); } catch (Exception e){}; System.out.println("Productor "+i);

Múltiples productores y consumidores public class UsaProdCons { public static void main(String[] args){ final int numCons = 5; Buffer b = new Buffer(5,numCons); Productor p = new Productor(b,1); Consumidor[] c = new Consumidor[numCons]; for (int i = 0; i<numCons; i++) c[i] = new Consumidor(b,i); System.out.println("comienza el programa"); Thread ph = new Thread(p); Thread[] ch = new Thread[numCons]; for (int i = 0; i<numCons; i++) ch[i] = new Thread(c[i]); for (int i = 0; i<numCons; i++) ch[i].start(); ph.start(); }

Múltiples productores y consumidores con notifyAll public synchronized void poner(int id,int d) throws InterruptedException{ System.out.println("productor " + id + "quiere poner "+d); while (numDatos == tam) { wait();} System.out.println("productor "+ id + " escribe en el buffer"); b[i] = d; for (int c = 0; c < nlectores ; c++) fdatos[c]++; flect[i] = nlectores; i = (i + 1) % tam; numDatos++; notifyAll(); } Hay un nuevo dato y aviso a todos

Lectores/Escritores (v. injusta) public class ControlBD { private int nLectores = 0; private boolean escribiendo = false; public synchronized void OpenL(int i) throws Exception{ while (escribiendo) wait(); nLectores++; System.out.println("Entra lector "+i); } public synchronized void OpenE(int i) throws Exception{ while (escribiendo || (nLectores > 0)) wait(); escribiendo = true; System.out.println("Entra escritor "+i); ......

Lectores/Escritores (v. injusta) public synchronized void CloseL(int i) throws Exception{ nLectores--; if (nLectores == 0) notifyAll(); System.out.println("Sale lector "+i); } public synchronized void CloseE(int i) throws Exception{ escribiendo = false; notifyAll(); System.out.println("Sale escritor "+i);

Lectores/Escritores (v. injusta) public class Escritor implements Runnable{ int miId; ControlBD c; public Escritor(int id,ControlBD c){ miId = id; this.c = c; } public void run(){ for (int i = 0; i < 10; i++){ try{ c.OpenE(miId); Thread.sleep(1); c.CloseE(miId); catch (Exception e){};

Lectores/Escritores (v. injusta) public class Lector implements Runnable{ int miId; ControlBD c; public Lector(int id,ControlBD c){ miId = id;this.c = c; } public void run(){ for (int i = 0; i < 10; i++){ try{ c.OpenL(miId); Thread.sleep(1); c.CloseL(miId); catch (Exception e){};

Lectores/Escritores El tener solo una cola de espera puede ser ineficiente si despertamos a procesos que no pueden continuar su ejecución porque todavía no se satisface la condición por la que esperan.

Lectores/Escritores (v. justa) public class ControlBD { private int nLectores = 0; private boolean escribiendo = false; private int nEscritores = 0; public synchronized void OpenL(int i) throws Exception{ while (escribiendo || (nEscritores > 0)) { System.out.println("Lector quiere entrar "+i); wait(); } nLectores++; ..............

Lectores/Escritores (v. justa) public synchronized void OpenE(int i) throws Exception{ nEscritores++; while (escribiendo || (nLectores > 0)) { System.out.println("Escritor quiere entrar "+i); wait(); } escribiendo = true;

Lectores/Escritores (v. justa) public synchronized void CloseL(int i) throws Exception{ nLectores--; if (nLectores == 0) notifyAll(); } public synchronized void CloseE(int i) throws Exception{ nEscritores--; escribiendo = false; notifyAll(); Despierta a todos

Lectores/Escritores (v. justa) public synchronized void CloseL(int i) throws Exception{ nLectores--; if (nLectores == 0) notifyAll(); } public synchronized void CloseE(int i) throws Exception{ nEscritores--; escribiendo = false; notifyAll(); Despierta a todos

Lectores/Escritores (v. justa) comienza Lectores/Escritores Escritor quiere entrar 0 Escritor quiere entrar 1 Lector quiere entrar 0 Lector quiere entrar 1 Lector quiere entrar 2 Lector quiere entrar 3 Lector quiere entrar 4 Lector quiere entrar 5 Lector quiere entrar 6 Lector quiere entrar 7 Lector quiere entrar 8 Lector quiere entrar 9 Lector quiere entrar 10 Lector quiere entrar 11 Lector quiere entrar 12 Lector quiere entrar 13 ................................... Hasta 350 intentos fallidos para 15 Lectores y 2 Escritores

Llamadas anidadas a métodos sincronizados Para que h ejecute e.p(), debe obtener el lock de e Hebra h class Ejemplo{ public synchronized void p(){ .......... } Ejemplo e = --- e.p()

Llamadas anidadas a métodos sincronizados class Ejemplo2{ public synchronized void p(){ .......... } Hebra h tiene lock(e) class Ejemplo{ public synchronized void p(){ .......... } Ejemplo2 e1 = .... Ejemplo e = --- e.p() e1.p() Para que e ejecute e1.p() debe obtener el lock de e1

Llamadas anidadas a métodos sincronizados class Ejemplo2{ public synchronized void p(){ .......... } Hebra h tiene lock(e), lock(e1) class Ejemplo{ public synchronized void p(){ .......... } Ejemplo2 e1 = .... Ejemplo e = --- e.p() e1.p()

Llamadas anidadas a métodos sincronizados class Ejemplo2{ public synchronized void p(){ .......... wait() } Hebra h tiene lock(e) class Ejemplo{ public synchronized void p(){ .......... } Ejemplo2 e1 = .... Ejemplo e = --- e.p() e1.p() Si se ejecuta wait(), se libera el lock de e1, pero se mantiene el de e, lo que puede producir bloqueos

Productor/Consumidor con condiciones y bloqueo public class Condition { public synchronized void delay(){ try{wait(); // suspende a la hebra que lo ejecuta }catch (Exception e){}; } public synchronized void resume(){ try{notify(); // despierta una hebra suspendida

Productor/Consumidor con condiciones y bloqueo public class Buffer { private int[] b; private int tam; private int i=0; private int j=0; private int numDatos = 0; private final Condition nolleno = new Condition(); private final Condition novacio = new Condition(); public Buffer(int t){ tam = t; b = new int[tam]; } .......

Productor/Consumidor con condiciones y bloqueo public synchronized void poner(int d) throws InterruptedException{ while (numDatos == tam) nolleno.delay(); b[i] = d; i = (i + 1) % tam; numDatos++; novacio.resume(); } public synchronized int extraer() throws InterruptedException{ while (numDatos == 0) novacio.delay(); int aux = j; j = (j + 1) % tam; numDatos--; nolleno.resume(); return b[aux]; Bloquea a la hebra Buffer Bloquea a la hebra Buffer

Locks Los métodos/instrucciones synchronized modelan el acceso exclusivo a lock de un monitor implícito asociado a un objeto, típicamente un recurso compartido por varias hebras. Sin embargo, cuando una hebra necesita usar más de un recurso, debe liberar los locks de los recursos en orden inverso a como se han obtenido, lo que en ocasiones puede no ser adecuado .... A.acquire(); B.acquire(); C.acquire(); A.release(); D.acquire(); B.release(); ......

Locks public class ReentrantLock ReentrantLock l = new ReentrantLock(); Un Lock para la exclusión mutua con la misma semántica y comportamiento que el lock implícito tipo monitor de los métodos e instrucciones sincronizadas (synchronized), pero con más posibilidades.

Locks: el problema de los jardines Implementación de la interfaz lock public class Cont { Lock l = new ReentrantLock(); private int c = 0; public void inc(int i){ l.lock(); try{ c++; } finally { l.unlock(); } Pido el lock Devuelvo el lock

Locks: el problema de los jardines public int valor(){ l.lock(); try{ return c; } finally { l.unlock(); } Pido el lock Devuelvo el lock La cláusula try/finally es necesaria para devolver el lock después de ejecutar return

Locks: condiciones Para modelar las condiciones de sincronización usamos la Interfaz Condition. public interface Condition Las condiciones clasifican los métodos del monitor (wait, notify and notifyAll) en distintos objetos de forma que es posible tener múltiples conjuntos de espera por objeto, asociados a locks. Lock l = new ReentrantLock() Condition c1 = l.newCondition(); Condition c2 = l.newCondition(); Las condiciones se asocian a locks y pueden definirse tantas como sea necesario

Locks: condiciones Métodos void await() throws InterruptedException Suspende a la hebra en la condición correspondiente void signal() Despierta una de las hebras que espera. La hebra tiene que conseguir el lock correspondiente antes de continuar su ejecución. (disciplina signal-and-continue) void signalAll() Desperta a todas las hebras que esperan. Cada hebra tiene que conseguir el lock correspondiente antes de continuar su ejecución.

Locks: condiciones Lock l = new ReentrantLock() Condition c1 = l.newCondition(); Condition c2 = l.newCondition(); l.lock(); try { while (!condicion1) c1.await(); // mientras !condicion1 espera en c1 // condicion1 se satisface // cambia el estado del objeto y condicion2 es cierta c2.signal(); // despertar una hebra que espera } finally { l.unlock(); }

Productor/Consumidor package condicion; import java.util.concurrent.locks.*; public class Buffer { private int[] b; private int tam; private int i=0; private int j=0; private int numDatos = 0; private final ReentrantLock lockBuffer = new ReentrantLock(); private final Condition nolleno = lockBuffer.newCondition(); private final Condition novacio = lockBuffer.newCondition(); public Buffer(int t){ tam = t; b = new int[tam]; } .........

Productor/Consumidor public void poner(int d) throws InterruptedException{ System.out.println("productor quiere poner "+d); try{ lockBuffer.lock(); while (numDatos == tam) nolleno.await(); b[i] = d; i = (i + 1) % tam; numDatos++; novacio.signal(); }finally{lockBuffer.unlock();} }

Productor/Consumidor public int extraer() throws InterruptedException{ System.out.println("consumidor quiere extraer" + numDatos); try{ lockBuffer.lock(); while (numDatos == 0) novacio.await(); int aux = j; j = (j + 1) % tam; numDatos--; nolleno.signal(); return b[aux]; } finally {lockBuffer.unlock();} }

Barbero Dormilón import java.util.concurrent.locks.*; public class Barberia { private Lock BLock = new ReentrantLock(); private Condition cBlibre = BLock.newCondition(); private Condition cSillaOcupada = BLock.newCondition(); private Condition cPuertaAbierta = BLock.newCondition(); private Condition cSiguiente = BLock.newCondition(); private boolean Blibre = false; private boolean SillaOcupada = false; private boolean PAbierta = false;

Barbero Dormilón public void siguiente(){ BLock.lock(); try{ System.out.println("Barbero libre"); Blibre = true; cBlibre.signal(); while (!SillaOcupada) try{cSillaOcupada.await();} catch (InterruptedException e){} }finally { BLock.unlock(); }

Barbero Dormilón public void finPelar(){ BLock.lock(); try{ PAbierta = true; cPuertaAbierta.signal(); while (PAbierta) try{cSiguiente.await();} catch (InterruptedException e){}; }finally { BLock.unlock(); }

Barbero Dormilón public void qPelar(int i){ BLock.lock(); try{ while (!Blibre) try{cBlibre.await();} catch (InterruptedException e){}; Blibre = false; SillaOcupada = true; System.out.println("Cliente "+i+" se sienta en la silla"); cSillaOcupada.signal(); while (!PAbierta) try{cPuertaAbierta.await();} System.out.println("Cliente "+i+" se va"); PAbierta = false; cSiguiente.signal(); }finally { BLock.unlock(); }

Barbero Dormilón public void qPelar(int i){ BLock.lock(); try{ while (!Blibre) try{cBlibre.await();} catch (InterruptedException e){}; Blibre = false; SillaOcupada = true; System.out.println("Cliente "+i+" se sienta en la silla"); cSillaOcupada.signal(); while (!PAbierta) try{cPuertaAbierta.await();} System.out.println("Cliente "+i+" se va"); PAbierta = false; cSiguiente.signal(); }finally { BLock.unlock(); }}}

Barbero Dormilón public class Barbero implements Runnable { Barberia b; public Barbero(Barberia b){ this.b = b; } public void run(){ while (true){ b.siguiente(); System.out.println("Barbero Pela Cliente"); // Barbero pela cliente b.finPelar();

Barbero Dormilón public class cliente implements Runnable{ Barberia b; int id; public cliente(Barberia b,int i){ this.b = b; id = i; } public void run(){ b.qPelar(id);

Barbero Dormilón public class UsaBarberia { public static void main(String[] args){ final int N = 125; Barberia b = new Barberia(); Barbero bar = new Barbero(b); cliente[] c = new cliente[N]; for (int i = 0; i<N; i++) c[i] = new cliente(b,i); Thread bh = new Thread(bar); bh.start(); Thread[] ch = new Thread[N]; ch[i]= new Thread(c[i]); ch[i].start(); }