{ "version": "2", "formats": { "markdown": { "content": "## Page 1\n\nUnidad 1\nProgramación concurrente\n\nTema 3 Dependencias de estados\n\n<page_number>1</page_number>\n\n---\n\n\n## Page 2\n\n# Contenidos\n\n1. Dependencias de estado\n2. Cómo enfrentarse a fallos\n * Excepciones\n * Cancelación\n3. Métodos protegidos\n * Suspensión protegida\n * Funcionamiento del monitor\n * Esperas con protección y notificaciones\n * Más tipos de esperas y notificaciones\n * Uso de bibliotecas\n4. Patrones de diseño concurrentes\n * Productor – Consumidor\n * Bloqueo de lectura y escritura\n5. Bibliografía\n\n<page_number>2</page_number>\n\n---\n\n\n## Page 3\n\n# Dependencias de estado\n\n* Para realizar cualquier acción (ej: tomar nota de un mensaje telefónico) se precisa dos condiciones:\n * **Externas**: un objeto recibe un mensaje que solicita la realización de la acción\n * **Internas**: el objeto se encuentra en el estado adecuado para realizar la acción\n* Las técnicas de **exclusión** preservan los **invariantes del objeto** ... el control de concurrencia **dependiente del estado** impone problemas adicionales relativos a las **precondiciones y postcondiciones**\n* Las acciones pueden tener precondicones que no siempre se cumplen y postcondiciones que no siempre se pueden alcanzar\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
Suena el teléfonoTengo bolígrafoNo tengo bolígrafo
Tomar el mensajeResponder al teléfonoResponder al teléfono
Escribir el mensaje????
\n\n<page_number>3</page_number>\n\n---\n\n\n## Page 4\n\n# Dependencias de estado\n\n* En un sistema ideal todos los métodos carecen de precondiciones basadas en su estado y siempre satisfacen sus postcondiciones\n * No siempre se pueden definir acciones no dependientes del estado\n* Dos estrategias de diseño\n 1. Optimista imposición vivacidad\n * Los métodos de tipo probar y ver siempre nos permiten probar cuando se invocan, pero no siempre tienen éxito, por tanto, pueden tener que enfrentarse a fallos\n * Se basan en la existencia de excepciones y otros mecanismos que indican el momento en el que no se satisfacen las postcondiciones\n\n<page_number>4</page_number>\n\n---\n\n\n## Page 5\n\n# Dependencias de estado\n\n## Dos estrategias de diseño\n\n### 2. Conservador imposición seguridad\n\n- Los métodos del tipo **comprobar** y **actuar** se niegan a seguir adelante salvo que se cumplan las precondiciones. Cuando las precondiciones son válidas las acciones siempre tienen éxito\n- Se basan en estructuras de protección que garantizan cuando son válidas las precondiciones y seguirán siendo válidas durante el transcurso de la acción\n\n* La combinación de ambas estrategias es posible y frecuente\n* Las acciones dependientes del estado requieren un esfuerzo y atención en la programación concurrente\n\n<page_number>5</page_number>\n\n---\n\n\n## Page 6\n\n# Cómo enfrentarse a fallos\n\n* La necesidad de estrategias probar y ver suelen surgir cuando no se quiere\\* o no se puede probar las **precondiciones**\n* No existen estructuras para definir la comprobación\n * Probar que un cerrojo se mantiene activado\n* Precondiciones con ámbito temporal (restricciones de activación)\n * Sistema de archivos que tiene espacio cuando entra en el método pero cuando escribe se queda sin espacio\n* Condiciones que cambian por señales procedentes de otros hilos\n * Cancelación en modo asíncrono\n* Condiciones muy costosas computacionalmente\\*\n * Comprobar que una matriz esté normalizada en forma triangular superior\n\n<page_number>6</page_number>\n\n---\n\n\n## Page 7\n\n# Cómo enfrentarse a fallos\n## Excepciones\n\n* La concurrencia introduce la posibilidad de que falle cierta parte del programa mientras otras siguen adelante\n* Los métodos pueden lanzar excepciones cuando han detectado que sus **postcondiciones** no pueden llevarse a efecto (fallo)\n* Las acciones fallidas tienen seis posibles respuestas:\n * Finalización súbita -NullPointerException-\n * Continuación -Notificación fallida listener animación-\n * Vuelta atrás -Falta de interferencia con otros hilos-\n * Avance o recuperación -Alcanzar un punto seguro-\n * Reintentos\n * Manejadores\n\n<page_number>7</page_number>\n\n---\n\n\n## Page 8\n\n# Cómo enfrentarse a fallos\n## Excepciones\n\n* Reintentos\n * Pueden consumir cantidades ilimitadas de CPU\n - Soluciones\n 1. Limitar el número de intentos\n 2. Añadir retardos temporales en el tiempo\n\n```java\nclass ClientUsingSocket { // Code sketch\n int portnumber = 1234;\n String server = \"gee\";\n // ...\n Socket retryUntilConnected() throws InterruptedException {\n // first delay is randomly chosen between 5 and 10secs\n long delayTime = 5000 + (long) (Math.random() * 5000);\n for (;;) {\n try {\n return new Socket(server, portnumber);\n } catch (IOException ex) {\n Thread.sleep(delayTime);\n delayTime = delayTime * 3 / 2 + 1; // increase 50%\n }\n }\n }\n}\n```\n\n<img>Blue V icon</img> <img>Green circle with white checkmark icon</img>\n<page_number>8</page_number>\n\n---\n\n\n## Page 9\n\n# Cómo enfrentarse a fallos\n## Excepciones\n\n* **Manejadores**\n * Se puede delegar las operaciones de tratamiento de errores en **manejadores centralizados**\n * El manejador puede realizar acciones de compensación en otros hilos del sistema\n * Difícil de realizar sin el control centralizado\n * El código es más extensible y flexible cuando lo usan clientes que no saben como responder a fallos\n * Se puede sustituir excepciones por retrollamadas, eventos otras técnicas de notificación\n * Tener cuidado cuando las notificaciones escapen el control de flujo basado en pila que proporcionan las excepciones\n\n<page_number>9</page_number>\n\n---\n\n\n## Page 10\n\n# Cómo enfrentarse a fallos\n## Excepciones\n\n* Manejadores\n\n```mermaid\nclassDiagram\n class <> ManejadorDeExcepcionServicio {\n +manejar(e:ExcepcionDeServicio)\n }\n class <> ServidorConExcepcion {\n +servicio() throws ExcepcionDeServicio\n }\n class <> ServidorManejado {\n +servicio()\n }\n class <> ServidorImpl {\n +servicio()\n }\n ManejadorDeExcepcionServicio <|-- ManejadorImpl\n ServidorConExcepcion <|-- ServidorManejado\n ServidorManejado \"1\" -- \"1\" ServidorImpl : servidor\n```\n\n```java\nclass ServidorManejado implements ServidorConExcepcion {\n final ServidorConExcepcion servidor = new ServidorImpl();\n final ManejadorDeExcepcionServicio manejador = new ManejadorImpl();\n\n public void servicio() { // sin sentencia throw\n try {\n servidor.servicio();\n } catch (ExcepcionDeServicio e) {\n manejador.manejar(e);\n }\n }\n}\n```\n\n<img>Blue V icon</img> <img>Green checkmark icon</img>\n<page_number>10</page_number>\n\n---\n\n\n## Page 11\n\n# Cómo enfrentarse a fallos\n## Cancelaciones\n\n* Cuando las actividades de un hilo experimentan un fallo o cambian de rumbo puede ser necesario cancelar actividades de otros hilos independientemente de lo que estén haciendo\n* Las solicitudes de cancelación introducen situaciones de fallo inherentemente impredecibles para los hilos que se están ejecutando\n* La naturaleza de la cancelación es asíncrona\n\nLos programas concurrentes tienen la obligación adicional de asegurar un estado coherente de los objetos internos que participen en varios hilos\n\n<page_number>11</page_number>\n\n---\n\n\n## Page 12\n\n# Cómo enfrentarse a fallos\n## Cancelaciones\n\n* La cancelación es un fenómeno natural en la mayoría de programas multihilos\n* Actividades asociadas al botón Cancelar de un GUI\n* Terminación de bucles de animación en actividades multimedia\n* Hilos que producen resultados que no se necesitan\n* Conjunto de actividades que no pueden proseguir porque una o más han encontrado errores o excepciones inesperadas\n\n<page_number>12</page_number>\n\n---\n\n\n## Page 13\n\n# Cómo enfrentarse a fallos\n## Cancelaciones\n\n* Interrupción\n * La técnica mejor soportada para abordar la cancelación se basa en el estado de interrupción de los hilos\n * Se configura mediante `Thread.interrupt()`\n * No impone una terminación inmediata permite que el hilo interrumpido pueda hacer operaciones de limpieza\n * Se inspecciona mediante `Thread.isInterrupted()`\n * Se borra mediante `Thread.interrupted()`\n * Se responde en algunas ocasiones lanzando una `InterruptedException`\n * Las interrupciones de hilos sirven como solicitudes de cancelación de actividades\n * La carencia de interrupciones se puede utilizar como precondición que se comprobará en los puntos seguros\n\n<page_number>13</page_number>\n\n---\n\n\n## Page 14\n\n# Cómo enfrentarse a fallos\n## Cancelaciones\n\n* Interrupción\n * Las comprobaciones de interrupción se realizan automáticamente dentro `Object.wait()`\n Thread.join() Thread.sleep()\n * Finalizan cuando se produce la interrupción lanzando InterruptedException\n * Permite a los hilos despertar y aplicar el código de cancelación\n* Existen dos situaciones en las que los hilos no pueden comprobar el estado de las interrupciones o recibir InterruptedException\n * En bloqueos de cierres sincronizados\n * En operaciones de E/S\n\n<page_number>14</page_number>\n\n---\n\n\n## Page 15\n\n# Métodos protegidos\n\n* Los métodos conservadores del tipo **comprobar y actuar** no realizan ciertas operaciones si no se cumplen sus **precondiciones**\n* Tipos de acciones en caso de no cumplimiento de las precondiciones:\n * **Rechazo**\n * Lanzar una excepción si no se cumplen las precondiciones\n * **Suspensión protegida** – no tiene analogía en programas secuenciales-\n * Suspender la invocación actual del método hasta que se cumpla la precondición\n * **Plazos temporales** – no tiene analogía en programas secuenciales-\n * Se establece una cota temporal de espera hasta que la precondición pase a ser verdadera\n\n<page_number>15</page_number>\n\n---\n\n\n## Page 16\n\n# Métodos protegidos\n## Suspensión con protección\n\n* Contexto del problema\n * Contador limitado\n\n```java\ninterface ContadorLimitado {\n static final long MIN = 0; // mínimo valor permitido\n static final long MAX = 10; // máximo valor permitido\n\n long getValor(); // INV: MIN <= getValor() <= MAX\n // INIT: getValor() == MIN\n void inc(); // PRE: getValor() < MAX\n void dec(); // PRE: getValor() > MIN\n}\n```\n\n<img>Blue V icon</img> <img>Green circle with white checkmark icon</img>\n<page_number>16</page_number>\n\n---\n\n\n## Page 17\n\n# Métodos protegidos\n## Suspensión con protección\n\n* Definición de estados lógicos\n * Conjunto de estados limitados para proteger las acciones\n\n\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
EstadoCondicióninc()dec()
superiorgetValor() == MAXno
medioMIN < getValor() <MAX
inferiorgetValor() == MINno
\n\n\ngraph LR\n A[Superior] -->|Dec desde MAX| B[Medio]\n B -->|Dec a MIN| C[Inferior]\n C -->|Inc desde MIN| B\n B -->|Inc a MAX| A\n\n\n<page_number>17</page_number>\n\n---\n\n\n## Page 18\n\n# Métodos protegidos\n## Suspensión con protección\n\n* **Definición de estados lógicos**\n * Muchos objetos que mantienen atributos que, en su conjunto, constituyen un espacio de estados muy grande, pero solamente mantienen un pequeño espacio lógico de estados para proteger sus acciones\n* Es preciso tener cuidado a la hora de caracterizar estos estados\n * Si MAX es igual a MIN+1 no existe estado intermedio\n * Si MAX es igual a MIN no hay forma de distinguir el estado Superior del Inferior.\n* **Representación** de los estados lógicos\n * Mediante una variable de rol, representando cada estado distinto mediante un nuevo valor.\n * Objetos como estados PD Estado\n\n<page_number>18</page_number>\n\n---\n\n\n## Page 19\n\n# Métodos protegidos\n\n## Funcionamiento del monitor (C.A.R. Hoare en 1974)\n\n* Las implementaciones de la suspensión con protección:\n * Usan los métodos `Object.wait()`, `Object.notify()`, `Object.notifyAll()`\n * Se basan en la siguiente estrategia\n * Para cada condición que sea preciso esperar se escribe un **bucle wait()** protegido que da lugar a que el hilo actual se bloquee si la condición de protección es falsa\n * Se asegura que todos los métodos que dan lugar a cambio de estado que afecten al valor de cualquier condición de espera, **notificarán (notify())** el cambio de estado para que los hilos despierten y vuelvan a comprobar condición de protección\n * El método `wait()` hace que el thread actual espere hasta que otro thread se lo notifique (`notify()`) o cambie una condición\n\n<page_number>19</page_number>\n\n---\n\n\n## Page 20\n\n# Métodos protegidos\n\n## Funcionamiento del monitor (C.A.R. Hoare en 1974)\n\n* Las entidades que poseen tanto **cerrojos** como **conjuntos de espera** se denominan **monitores**\n* La clase `java.lang.Object` puede servir de monitor\n * Tiene un **cerrojo** (`synchronized`)\n * Tiene un **conjunto de espera** que manipula mediante\n - `wait`, `notify`, `notifyAll`, `Thread.interrupt`\n* Los métodos `wait`, `notify`, `notifyAll` solamente se pueden invocar cuando el objeto haya adquirido el **manejo de la sincronización**\n * `IllegalMonitorStateException`\n\n<page_number>20</page_number>\n\n---\n\n\n## Page 21\n\n# Métodos protegidos\n\n## Funcionamiento del monitor (C.A.R. Hoare en 1974)\n\n* **Acciones asociadas a wait y notify**\n\n * `wait()`\n * La JVM pone el hilo en el conjunto de espera interno asociado al objeto en cuestión (recurso)\n * Se libera el cerrojo de sincronización correspondiente al objeto en cuestión (recurso), se mantienen todos los demás cerrojos que haya adquirido el hilo\n\n * `wait(long milisegundos)` Esperas temporizadas\n * Admite un argumento que especifica el tiempo máximo deseado de permanencia en el conjunto de espera\n * Funciona del mismo modo que la versión no temporizada salvo que, si no se ha notificado una espera antes de concluir sus límites de tiempo, la liberación se produce automáticamente\n\n<page_number>21</page_number>\n\n---\n\n\n## Page 22\n\n# Métodos protegidos\n\n## Funcionamiento del monitor (C.A.R. Hoare en 1974)\n\n* `notify()`\n * Si existe algún hilo en estado de espera interno asociado al objeto cerrojo, la JVM saca del conjunto de espera un hilo arbitrario, digamos **T**\n * Si existen varios hilos en el conjunto de espera no existe una garantía de conocer cual de los hilos se elige\n * **T** pasa a un estado de listo, debe obtener el cerrojo de sincronización y esperará.\n * **T** no pasará a un estado en ejecución hasta que el hilo que llama a `notify()` no libera el cerrojo\n * **T** reanuda desde el punto siguiente a su `wait()`\n\n<page_number>22</page_number>\n\n---\n\n\n## Page 23\n\n# Métodos protegidos\n\n## Funcionamiento del monitor (C.A.R. Hoare en 1974)\n\n**notifyAll()**\n* Su funcionamiento es similar a notify()\n* Saca todos los hilos que se encuentren en conjunto de espera\n\n**Thread.interrupt()**\n* Su funcionamiento es similar a notify() para un hilo que esté suspendido en un wait, salvo que, una vez vuelto a adquirir el cerrojo el método lanza una InterruptedException y actualiza el valor del estado de interrupción del hilo a false\n\n<page_number>23</page_number>\n\n---\n\n\n## Page 24\n\n# Métodos protegidos\n\n## Funcionamiento del monitor (C.A.R. Hoare en 1974)\n\n* Ejemplo para explicar la mecánica subyacente de `wait` `notify`\n* Ejemplo inútil desde el punto de vista funcional\n* Analizar un posible resultado de ejecución cuando existen tres hilos( T1, T2, T3 ) que invocan a métodos pertenecientes a un cierto objeto x de tipo X común\n\n```java\npublic class X{\n public synchronized void w() throws InterruptedException{\n antes(); wait(); despues();\n }\n public synchronized void n(){\n notifyAll();\n }\n protected void antes(){}\n protected void despues(){}\n}\n```\n\n<img>V logo</img>\n<page_number>24</page_number>\n\n---\n\n\n## Page 25\n\n# Métodos protegidos\n## Funcionamiento del monitor (C.A.R. Hoare en 1974)\n\n\ngraph TD\n subgraph Theads\n T1[T1]\n T2[T2]\n T3[T3]\n end\n\n subgraph Tiempo\n direction LR\n A[ ] -- \" \" --> B[ ]\n B[ ] -- \"0\" --> C[ ]\n C[ ] -- \"1\" --> D[ ]\n D[ ] -- \"2\" --> E[ ]\n E[ ] -- \"3\" --> F[ ]\n F[ ] -- \"4\" --> G[ ]\n G[ ] -- \"5\" --> H[ ]\n H[ ] -- \"6\" --> I[ ]\n I[ ] -- \"7\" --> J[ ]\n J[ ] -- \"8\" --> K[ ]\n K[ ] -- \"9\" --> L[ ]\n L[ ] -- \"10\" --> M[ ]\n M[ ] -- \" \" --> N[ ]\n end\n\n subgraph Threads\n TW1[T1]\n TW2[T2]\n TW3[T3]\n end\n\n TW1 --> T1\n TW2 --> T2\n TW3 --> T3\n\n subgraph Monitor\n M1[begin x.w()]\n M2[adquirir cerrojo]\n M3[antes()]\n M4[wait:]\n M5[liberar cerrojo]\n end\n\n subgraph Thread 1\n T1A[begin x.w()
adquirir cerroj
antes()
wait:
liberar cerrojo
entrar en conjunto
de espera]\n end\n\n subgraph Thread 2\n T2A[begin x.w()
adquirir cerroj
antes()
wait:
liberar cerrojo
entrar en conjunto
de espera]\n end\n\n subgraph Thread 3\n T3A[begin x.n()
esperar bloqueo
adquirir cerrojo < br> notifyAll();
liberar cerrojo]\n end\n\n T1A --> M1\n T1A -- \" \" --> T2A\n T1B --> M1\n end\n\n subgraph Monitor\n M6[salir del conjunto
de espera
esperar bloqueo]\n M7[adquirir cerrojo
despues()
liberar cerrojo]\n end\n\n T1B --> M6\n T2B --> M6\n\n subgraph Thread 1\n T1B[salir del conjunto
de espera
esperar bloqueo
adquirir cerrojo
despues()
liberar cerrojo]\n end\n\n subgraph Monitor\n M8[adquirir cerroj
despue:
liberac]\n end\n\n T1B --> M8\n T2B --> M8\n\n subgraph Thread 2\n T2C[adquirir
despues()
liberar]\n end\n\n T2B --> T2C\n T2C --> M8\n\nend\n\nDoug Lea. Programación concurrente en Java: Principios y patrones de diseño. 2ª ed. PEARSON EDUCACION, 2000. Pag. 192\n<page_number>25</page_number>\n\n---\n\n\n## Page 26\n\n# Métodos protegidos\n## Esperas con protección y notificaciones\n\n```java\nclass CountadorLimitadoSimple {\n\n static final long MIN = 0; // mínimo valor permitido\n static final long MAX = 10; // máximo valor permitido\n\n protected long valor = MIN;\n\n public synchronized long getValor() {\n return valor;\n }\n\n public synchronized void inc() throws InterruptedException {\n esperarSalirEstadoSuperior();\n setValor(valor + 1);\n }\n\n protected void esperarSalirEstadoSuperior() throws InterruptedException {\n while (valor == MAX)\n wait();\n }\n}\n```\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
EstadoCondicióninc()dec()
superiorgetValor() == MAXno
medioMIN < getValor() <MAX
inferiorgetValor() == MINno
\n\n<img>Blue V icon</img> <img>Green circle with white checkmark icon</img>\n\n<page_number>26</page_number>\n\n---\n\n\n## Page 27\n\n# Métodos protegidos\n## Esperas con protección y notificaciones\n\n// continua de la transparencia anterior\n\n```java\npublic synchronized void dec() throws InterruptedException {\n esperarSalirEstadoInferior();\n setValor(valor - 1);\n}\n```\n\n```java\nprotected void esperarSalirEstadoInferior() throws InterruptedException{\n while (valor == MIN)\n wait();\n}\n```\n\n```java\nprotected void setValor(long nuevoValor) { // PRE: bloqueo adquirido\n valor = nuevoValor;\n notifyAll(); // Despierta a todos los hilos que dependen del valor\n}\n```\n\n<img>V</img> <img>Checkmark</img>\n<page_number>27</page_number>\n\n---\n\n\n## Page 28\n\n# Métodos protegidos\n## Más tipos de esperas y notificaciones\n\n* **Esperas temporizadas**\n * En lugar de esperar indefinidamente a que una condición pase a ser verdadera dentro de un método protegido se imponen una cota superior de tiempo\n * - wait(long timeout)\n* **Notificaciones simples**\n * Mejora la eficiencia de computación en notificaciones innecesarias\n * Se despierta sólo a un hilo del conjunto de espera\n * - notify()\n\n<page_number>28</page_number>\n\n---\n\n\n## Page 29\n\n# Métodos protegidos\n## Más tipos de esperas y notificaciones\n\n* **Esperas ocupadas**\n * Se utiliza en estilos optimistas de reintentos con espera ocupada basada en un bucle activo\n* No utilizar con acciones protegidas\n\n```java\nprotected esperaOcupadaHastaCond() {\n while (!cond)\n Thread.yield();\n}\n```\n<img>V logo</img>\n\n<page_number>29</page_number>\n\n---\n\n\n## Page 30\n\n# Métodos protegidos\n## Uso de bibliotecas\n\n* **Adquisición de bloqueos sobre un objeto**\n * Interface `java.util.concurrent.locks.Lock`\n * Clase `java.util.concurrent.locks.ReentrantLock`\n * Constructor que recibe un booleano indicando si aplicar o no la política de equidad.\n * Si es true:\n * El objeto que lleva más tiempo esperando entra.\n * Evita la inanición (starvation) de las tareas: la tarea es incapaz de ganar el acceso al recurso y nunca pasa a ejecución “muriendo por inanición”\n * Permite volverse atrás en la adquisición de bloqueos\n * lock() para la adquisición, si está ocupado queda en espera.\n * unlock() para la liberación\n * tryLock() obtiene el bloqueo retornando true, sólo si esta libre en el momento de la petición, en caso contrario retorna inmediatamente un valor false.\n * lockInterruptibly() obtiene el bloqueo salvo que el hilo sea interrumpido.\n\n<page_number>30</page_number>\n\n---\n\n\n## Page 31\n\n# Métodos protegidos\n## Uso de bibliotecas\n\n* Condiciones para proseguir la tarea\n * newCondition de la interfaz Lock\n - Devuelve un objeto que implementa la interfaz java.util.concurrent.locks.Condition\n* Métodos sobre el objeto Condition obtenido:\n * await\n * libera el bloqueo coloca a la tarea en espera\n * similar al uso de condiciones y método wait\n * signal\n * hace que la tarea bloqueada con más tiempo de espera pase a ejecutable\n * similar al uso de condiciones y método notify\n * signalAll\n * hace que todas las tarea en espera pasen a ejecutable\n * similar al uso de condiciones y método notifyAll\n\n<page_number>31</page_number>\n\n---\n\n\n## Page 32\n\n# Métodos protegidos\n## Uso de bibliotecas\n\n* Uso de bloqueos (Lock) y condiciones (Condition)\n\n```java\nLock lock = new ReentrantLock();\nCondition condición1 = lock.newCondition();\n// podemos definir distintas condiciones\nCondition condición2 = lock.newCondition();\n\npublic void bloqueRestringidoConLockAndCondition() {\n lock.lock();\n try {\n while (!cond) { // restricción\n try {\n condición1.await(); // espera\n } catch (InterruptedException e) {\n e.printStackTrace();\n }\n }\n cond = false; // cambiar estado\n condición2.signalAll(); // liberar\n } finally {\n lock.unlock();\n }\n}\n```\n\n<img>V</img>\n<page_number>32</page_number>\n\n---\n\n\n## Page 33\n\n# Patrones de diseño concurrente\n## Productor- Consumidor\n\n* **Intención**\n * Coordinar la producción y consumo asíncrono de información\n* **Contexto**\n\n\ngraph LR\n subgraph PRODUCTOR\n A[Producir]\n B[Esperar]\n C[Comunicar]\n end\n\n subgraph CONSUMIDOR\n D[Consumir]\n E[Esperar]\n F[Comunicar]\n end\n\n A --> B\n B --> C\n C --> A\n\n E --> F\n F --> E\n\n style A fill:#f9f,stroke:#333,stroke-width:2px\n style D fill:#f9f,stroke:#333,stroke-width:2px\n\n\n**Paso de X**\n\n\n \n \n \n \n
\n 1. Notificar que productor no está preparado
\n 2. Efectuar cálculos que produzcan un valor de x
\n 3. Notificar que productor está preparado
\n 4. Esperar a que el consumidor esté preparado
\n 5. Pasar x al consumidor\n
\n 1. Notificar que consumidor está preparado
\n 2. Esperar a que el productor esté preparado
\n 3. Obtener x del productor
\n 4. Notificar que consumidor no está preparado
\n 5. Efectuar un cálculo que utiliza el valor de x\n
\n\n---\n\n\n## Page 34\n\n# Patrones de diseño concurrente\n## Productor- Consumidor\n\n* **Fuerzas** – cuando aplicar el patrón-\n * Los objetos son producidos o recibidos de **forma asíncrona** para su utilización o consumo\n * Cuando un objeto se recibe o se produce pero podría no haber objetos disponibles para ser usados o consumidos\n* **Solución**\n\n```mermaid\nclassDiagram\n class Dato {\n dato : Object\n +setDato(o:Object){conurrencia=espera | ¿hay espacio?}\n +getDato():Object {conurrencia=espera | ¿hay datos?}\n }\n class Producer {\n 0..* produce datos -> 1 Dato\n }\n class Consumer {\n 1 consume datos -> 0..* Dato\n }\n Producer --|> java.lang.Runnable : run()\n Consumer --|> java.lang.Runnable : run()\n```\n\n<page_number>34</page_number>\n\n---\n\n\n## Page 35\n\n# Patrones de diseño concurrente\n## Productor- Consumidor\n\n* **Ejemplo de código**\n\n```java\npublic class Dato {\n private int dato = -1;\n private boolean sepuedeescibir = true;\n public synchronized void setDato(int val) {\n while (!sepuedeescibir) {\n try {\n wait();\n } catch (InterruptedException e) {\n System.out.print(e.toString());\n }\n }\n dato = val;\n sepuedeescibir = false;\n notify();\n }\n public synchronized int getDato() {\n while (sepuedeescibir) {\n try {\n wait();\n } catch (InterruptedException e) {\n System.out.print(e.toString());\n }\n }\n sepuedeescibir = true;\n notify();\n return dato;\n }\n}\n```\n\n```java\npublic class Dato {\n private int dato = -1;\n\n public void setDato(int val){\n dato = val;\n }\n\n public int getDato(){\n return dato;\n }\n}\n```\n\n<img>Red arrow pointing to the right</img>\n<img>Blue circle with white checkmark</img> <img>Red circle with white cross</img>\n\n<page_number>35</page_number>\n\n---\n\n\n## Page 36\n\n# Patrones de diseño concurrente\n## Productor- Consumidor\n\n* **Ejemplo de código**\n\n```java\npublic class Consumidor extends Thread {\n private Dato recurso;\n public Consumidor(Dato r) {\n super(\"Consumidor\");\n recurso = r;\n }\n public void run() {\n int val, sum = 0;\n do {\n try {\n Thread.sleep((int)(Math.random() * 3000));\n } catch (InterruptedException e) {\n System.err.println(e.toString());\n }\n val = recurso.getDato();\n System.out.println(\" El consumidor recupero \" + val + \" del recurso compartido\\n\");\n sum++;\n } while (val != 5);\n System.out.println(\"Fin del consumidor: El número total de valores consumidos es:\" + sum);\n }\n}\n```\n\n<img>Blue V icon</img><img>Green checkmark icon</img>\n\n---\n\n\n## Page 37\n\n# Patrones de diseño concurrente\n## Productor- Consumidor\n\n* **Ejemplo de código**\n```java\npublic class Productor extends Thread {\n private Dato recurso;\n\n public Productor(Dato r) {\n super(\"Productor\");\n recurso = r;\n }\n\n public void run() {\n for (int contador = 1; contador <= 5; contador++) {\n try {\n Thread.sleep((int)(Math.random() * 3000));\n } catch (InterruptedException e) {\n System.err.println(e.toString());\n }\n recurso.setDato(contador);\n System.out.println(\" El productor puso \" + contador + \" en el recurso compartido\\n\");\n }\n }\n\n System.err.println(\"\\n*** Fin del productor:\");\n}\n```\n<img>Blue V logo</img><img>Green circle with white checkmark logo</img>\n\n---\n\n\n## Page 38\n\n# Patrones de diseño concurrente\n## Productor- Consumidor\n\n* Ejemplo de código\n\n```java\npublic class TestProductorConsumidor {\n public static void main(String args[]) {\n Dato r = new Dato();\n Productor p = new Productor(r);\n Consumidor c = new Consumidor(r);\n p.start();\n c.start();\n }\n}\n```\n<img>Blue V icon</img> <img>Green circle with checkmark icon</img>\n\nSalida de ejecución\n\nEl productor puso 1 en el recurso compartido\nEl consumidor recupero 1 del recurso compartido\nEl productor puso 2 en el recurso compartido\nEl consumidor recupero 2 del recurso compartido\nEl productor puso 3 en el recurso compartido\nEl consumidor recupero 3 del recurso compartido\nEl productor puso 4 en el recurso compartido\nEl consumidor recupero 4 del recurso compartido\nEl productor puso 5 en el recurso compartido\n*** Fin del productor:\nEl consumidor recupero 5 del recurso compartido\nFin del consumidor: El número total de valores consumidos es:5\n\n<img>Timeline diagram showing two threads (Consumidor and Productor) running concurrently. The timeline is labeled \"Threads\" with \"0:00\" and \"[m:s]\" at the top right. The legend at the bottom indicates colors for Running, Sleeping, Wait, and Monitor.</img>\n\n<page_number>38</page_number>\n\n---\n\n\n## Page 39\n\n# Patrones de diseño concurrente\n## Productor- Consumidor\n\n* Uso `java.util.concurrent.BlockingQueue`\n\n```java\nclass Producer implements Runnable {\n private final BlockingQueue queue;\n Producer(BlockingQueue q) {\n queue = q;\n }\n public void run() {\n try {\n while (true) { queue.put(produce()); }\n } catch (InterruptedException ex) { ... handle ... }\n }\n}\nObject produce() { ... }\n```\n\n```java\npublic class TestBlockingQueue {\n public static void main(String[] args) {\n BlockingQueue q = new SomeQueueImplementation();\n Producer p = new Producer(q);\n Consumer c1 = new Consumer(q);\n Consumer c2 = new Consumer(q);\n new Thread(p).start();\n new Thread(c1).start();\n new Thread(c2).start();\n }\n}\n```\n\n```java\nclass Consumer implements Runnable {\n private final BlockingQueue queue;\n Consumer(BlockingQueue q) {\n queue = q;\n }\n public void run() {\n try {\n while (true){ consume(queue.take()); }\n } catch (InterruptedException ex) {\n ... handle ...\n }\n }\n void consume(Object x) { ... }\n}\n\n---\n\n\n## Page 40\n\n# Patrones de diseño concurrente\n## Bloqueo Lectura/Escritura\n\n* **Intención**\n * Permitir accesos de lectura concurrente a un objeto pero se requiere accesos exclusivos para operaciones de escritura\n* **Fuerzas**\n * Hay necesidad de leer y escribir información de estado de un objeto\n * Pueden realizarse operaciones de lectura concurrentemente. La lectura es segura sólo si no hay operaciones de escritura ejecutándose concurrentemente\n * La lógica para coordinar las operaciones de lectura y escritura se puede reutilizar\n\n<page_number>40</page_number>\n\n---\n\n\n## Page 41\n\n# Patrones de diseño concurrente\n## Bloqueo Lectura/Escritura\n\n* **Solución**\n * La abstracción Dato utiliza los bloqueos coordinados de lectura y escritura\n\n```java\nimport java.util.concurrent.locks.ReadWriteLock;\nimport java.util.concurrent.locks.ReentrantReadWriteLock;\npublic class DatoRW {\n private int dato;\n private final ReadWriteLock lock = new ReentrantReadWriteLock();\n public DatoRW(int dato) {\n super();\n this.dato = dato;\n }\n public int getDato() {\n lock.readLock().lock();\n int datoaux = dato;\n lock.readLock().unlock();\n return datoaux;\n }\n public void setDato(int dato){\n lock.writeLock().lock();\n this.dato = dato;\n lock.writeLock().unlock();\n }\n}\n```\n\n```mermaid\nclassDiagram\n class Dato {\n dato : Object\n +setDato(o:Object){conurrencia=espera | ¿bloqueos de R o W?}\n +getDato():Object {conurrencia=espera | ¿bloqueos de W?}\n }\n class ReadWriteLock {\n readLock()\n writeLock()\n }\n Dato \"1\" -- \"*\" ReadWriteLock : Usa\n\n---\n\n\n## Page 42\n\n# Patrones de diseño concurrente\n## Bloqueo Lectura/Escritura\n\n* Solución\n\n```java\npublic abstract class ReadWrite {\n protected int activeReaders = 0; // threads executing read\n protected int activeWriters = 0; // always zero or one\n\n protected int waitingReaders = 0; // threads not yet in read\n protected int waitingWriters = 0; // same for write\n\n protected abstract void doRead(); // implement in subclasses\n\n protected abstract void doWrite();\n\n public void read() throws InterruptedException {\n beforeRead();\n try {\n doRead();\n } finally {\n afterRead();\n }\n }\n\n public void write() throws InterruptedException {\n beforeWrite();\n try {\n doWrite();\n } finally {\n afterWrite();\n }\n }\n\n protected boolean allowReader() {\n return waitingWriters == 0 && activeWriters == 0;\n }\n}\n```\n<page_number>42</page_number>\n\n---\n\n\n## Page 43\n\n# Patrones de diseño concurrente\n## Bloqueo Lectura/Escritura\n\n* Solución\n\n```java\nprotected boolean allowWriter() {\n return activeReaders == 0 && activeWriters == 0;\n}\n\nprotected synchronized void beforeRead() throws InterruptedException {\n ++waitingReaders;\n while (!allowReader()) {\n try {\n wait();\n } catch (InterruptedException ie) {\n --waitingReaders; // roll back state\n throw ie;\n }\n }\n --waitingReaders;\n ++activeReaders;\n}\n\nprotected synchronized void afterRead() {\n --activeReaders;\n notifyAll();\n}\n\nprotected synchronized void beforeWrite() throws InterruptedException {\n ++waitingWriters;\n while (!allowWriter()) {\n try {\n wait();\n } catch (InterruptedException ie) {\n --waitingWriters;\n throw ie;\n }\n }\n --waitingWriters;\n ++activeWriters;\n}\n\nprotected synchronized void afterWrite() {\n --activeWriters;\n notifyAll();\n}\n\n---\n\n\n## Page 44\n\n# Bibliografía\n\n* **Libros y manuales**\n * Doug Lea. Programación concurrente en Java: Principios y patrones de diseño. 2ª ed. PEARSON EDUCACION, 2000. Tema 3.\n http://gee.cs.oswego.edu/dl/cpj/.\n * Oracle. «Lesson: Concurrency (The Java™ Tutorials > Essential Classes)». Accedido enero 23, 2013.\n http://docs.oracle.com/javase/tutorial/essential/concurrency/index.html.\n * Grand, Mark. Patterns in Java. Volumen 1. A Catalog of Reusable Design Patterns Illustrated with UML. Wiley computer publishing. New York John Wiley and Sons Inc, 1998. Tema 9\n\n* **Enlaces de interés**\n * «Java Concurrent Animated | Free Home & Education software downloads at SourceForge.net». Accedido enero 23, 2013.\n http://sourceforge.net/projects/javaconcurrenta/.\n\n<page_number>44</page_number>", "metadata": {} } } }