java - sincronizacion - mutex sistemas operativos
¿Es mejor sincronizar con semáforos o con monitores? (4)
¿Es mejor sincronizar con semáforos o con monitores?
Para confirmar, por monitores nos referimos a la buena palabra clave synchronized
.
Primera pregunta, ¿necesitas tu candado para tener un contador?
- Un semáforo puede tener un contador mayor que uno . Si necesita proteger N recursos, el semáforo es el mejor. Decisión fácil
- Si está protegiendo un único recurso, este es el caso interesante en el que un semáforo (1) y un monitor son igualmente aplicables.
El artículo de simultaneidad de J2SE 5.0 ofrece excelentes consejos aquí. Los monitores están limitados porque:
- No hay manera de alejarse de un intento de adquirir un bloqueo que ya está retenido, o de rendirse después de esperar durante un período de tiempo específico, o de cancelar un intento de bloqueo después de una interrupción.
- No hay forma de alterar la semántica de un bloqueo, por ejemplo, con respecto a la reentrada, la protección de lectura frente a escritura o la equidad.
- La sincronización se realiza dentro de los métodos y bloques, lo que limita el uso al bloqueo estricto estructurado por bloques. En otras palabras, no puede adquirir un bloqueo en un método y liberarlo en otro .
Entonces, si alguno de estos elementos es importante para usted, retroceder después de un tiempo de espera es un gran ejemplo, entonces vaya con un semáforo. Si no, un monitor está bien.
"Mejor" depende del contexto. Ellos son "igualmente poderosos" según James McParlane. Recomiendo ver su blog para una discusión sobre las diferencias .
Aquí hay una guía rápida que encontré:
Semáforos
- Se puede usar en cualquier lugar de un programa, pero no se debe usar en un monitor
-
Wait()
no siempre bloquea al que llama (es decir, cuando el contador del semáforo es mayor que cero). -
Signal()
libera un hilo bloqueado, si hay uno, o aumenta el contador de semáforo. - Si
Signal()
libera un hilo bloqueado, tanto el que llama como el hilo liberado continúan.
Variables de condición
- Solo se puede usar en monitores
-
Wait()
siempre bloquea a la persona que llama. -
Signal()
libera un hilo bloqueado, si hay uno, o la señal se pierde como si nunca sucediera. - Si
Signal()
libera un hilo bloqueado, el llamador cede el monitor (tipo Hoare) o continúa (tipo Mesa). Solo uno de los llamantes o el hilo liberado puede continuar, pero no ambos.
Esta información de: http://www.cs.mtu.edu/~shene/NSF-3/e-Book/MONITOR/sema-vs-monitor.html
Algunos recursos útiles:
Si está buscando la minimización de dolor de cabeza, prefiera los monitores (bloques / métodos synchronized
) sobre semáforos donde sienta una elección real de una primitiva de bloqueo. Ignora la charla académica sobre la flexibilidad de los semáforos. Usted busca fiabilidad, no capacidad de configuración, ¿verdad?
A menudo se afirma que los monitores y semáforos son equivalentes (pueden simularse entre sí), pero esta equivalencia es mucho más abstracta y menos útil de lo que a veces se espera . Cualquiera que pueda simular correctamente uno con el otro ya no necesita ninguna respuesta a esta pregunta.
Obviamente, los semáforos son su única opción práctica en situaciones en las que el número de subprocesos que se permite ingresar simultáneamente a un bloque es mayor que uno. Entonces, el verdadero competidor de los monitores son los semáforos binarios , es decir, aquellos que se inicializan con un recuento de 1, y adicionalmente solo aquellos en los que se espera que el mismo hilo que realizó el bloqueo desbloquee eventualmente el semáforo. Entonces, miremos más de cerca exactamente esas situaciones.
La diferencia fundamental entre monitores y semáforos binarios es la propiedad del hilo . Tiene una gran consecuencia, y esa es la capacidad de reentrada . La reentrada significa que un hilo que ya posee un bloqueo puede adquirirlo nuevamente en lugar de bloquearlo. Esto es un gran problema si su clase ha compartido un estado que simplemente quiere proteger en todos los métodos, pero no puede permitirse suposiciones permanentes sobre cómo estos métodos se llaman entre sí; o con rasgos de cinturones y tirantes que evolucionan en su esquema de seguridad de hilos en general.
Los semáforos nunca vuelven a entrar y los monitores de Java siempre son reentrantes. Si necesita bloquear el mismo objeto desde muchas ubicaciones de código, los semáforos son propensos a interbloqueos incluso en escenarios de subproceso único, y esta limitación de semáforos ofrece beneficios solo en escenarios relativamente raros donde los monitores no son realmente una opción.
La propiedad de subprocesos también reduce drásticamente el riesgo de olvidarse de bloquear, olvidarse de desbloquear, o las actividades de un subproceso enmascaran las actividades de otro subproceso. También hay una diferencia ergonómica significativa en la sintaxis de Java asociada.
Note también esta pregunta ; aunque utiliza una terminología diferente, las mejores respuestas allí entienden que "mutex" significa un "monitor" de Java.
Antes que nada, debes decidir qué JDK estás usando. Las primeras versiones de Java solo están provistas de hilos. Desde Java Tiger (5.0), se han introducido nuevas clases para manejar la concurrencia. En particular, se ha proporcionado un paquete completo, el java.util.concurrent .
En mi experiencia, descubrí que los monitores son mejores, ya que dejan el código más limpio. Además, usarlos permite que el código sea más fácil de entender . Generalmente se implementan a través de una clase que implementa la interfaz Lock : las implementaciones más famosas proporcionadas por el JDK son la clase ReentrantLock , que define un bloqueo general, y la clase ReentrantReadWriteLock , que proporciona un bloqueo específico de escritura y / o lectura .
Por lo tanto, se usa un bloqueo para activar / desactivar el acceso a un objeto compartido (por ejemplo, una lista de objetos).
Un objeto Semaphore es un sincronizado que se utiliza para coordinar y controlar los hilos (hay muchos sincronizadores proporcionados en los últimos JDK, como las clases Semaphore , CyclicBarrier , CountdownLatch y Exchanger ). Por ejemplo, con un semáforo puede liberar un número fijo de tokens a su conjunto de subprocesos y así decidir la cantidad de operaciones que se pueden ejecutar simultáneamente. Personalmente, no me gusta este enfoque, ya que el uso de un conjunto de hilos con Futures y Locks conduce al mismo resultado de una manera más limpia y segura.
Se puede encontrar más información en este libro: " Concurrencia de Java en la práctica " y en este tutorial de IBM: " Concurrencia en JDK 5.0 ". Algunos ejemplos más agradables se pueden encontrar aquí .