java.util.concurrent
API proporciona una clase llamada as Lock
, que básicamente serializaría el control para acceder al recurso crítico. Da método como park()
y unpark()
.
Podemos hacer cosas similares si podemos usar synchronized
palabras clave y usar wait()
y notify() notifyAll()
métodos.
Me pregunto cuál de estos es mejor en la práctica y por qué.
Respuestas:
Si simplemente está bloqueando un objeto, preferiría usar
synchronized
Ejemplo:
Tienes que hacerlo explícitamente en
try{} finally{}
todas partes.Mientras que con sincronizado, es súper claro e imposible equivocarse:
Dicho esto,
Lock
s puede ser más útil para cosas más complicadas en las que no puede adquirir y liberar de una manera tan limpia. Sinceramente, preferiría evitar usar bareLock
s en primer lugar, y simplemente ir con un control de concurrencia más sofisticado, como aCyclicBarrier
o aLinkedBlockingQueue
, si satisfacen sus necesidades.Nunca he tenido una razón para usar
wait()
onotify()
pero puede haber algunas buenas.fuente
std::lock_guard
He descubierto que
Lock
yCondition
(y otrasconcurrent
clases nuevas ) son solo más herramientas para la caja de herramientas. Podía hacer casi todo lo que necesitaba con mi viejo martillo (lasynchronized
palabra clave), pero era difícil de usar en algunas situaciones. Varias de esas situaciones incómodas se volvieron mucho más simples una vez que agregué más herramientas a mi caja de herramientas: un mazo de goma, un martillo de bola, una palanca y algunos punzones. Sin embargo , mi viejo martillo todavía ve su parte de uso.No creo que uno sea realmente "mejor" que el otro, sino que cada uno es mejor para diferentes problemas. En pocas palabras, el modelo simple y la naturaleza orientada al alcance de
synchronized
me ayudan a protegerme de los errores en mi código, pero esas mismas ventajas son a veces obstáculos en escenarios más complejos. Es estos escenarios más complejos que el paquete concurrente se creó para ayudar a abordar. Pero el uso de estas construcciones de nivel superior requiere una administración más explícita y cuidadosa en el código.===
Creo que JavaDoc hace un buen trabajo al describir la distinción entre
Lock
ysynchronized
(el énfasis es mío):fuente
Usted puede lograr todo lo que las empresas de servicios públicos en java.util.concurrent hacen con las primitivas de bajo nivel como
synchronized
,volatile
o espera / notifiqueSin embargo, la concurrencia es complicada y la mayoría de las personas se equivocan al menos en algunas partes, lo que hace que su código sea incorrecto o ineficiente (o ambos).
La API concurrente proporciona un enfoque de nivel superior, que es más fácil (y, como tal, más seguro) de usar. En pocas palabras, ya no debería necesitar usarlo
synchronized, volatile, wait, notify
directamente.El bloqueo de la clase en sí está en el lado de bajo nivel de esta caja de herramientas, es posible que ni siquiera necesidad de usar que directa o bien (se puede utilizar
Queues
y semáforo y esas cosas, etc, la mayoría de las veces).fuente
java.util.concurrent
es más fácil [en general] que las características del lenguaje (synchronized
, etc.). Cuando lo usajava.util.concurrent
, tiene que acostumbrarse a completarlock.lock(); try { ... } finally { lock.unlock() }
antes de escribir el código, mientras que con unsynchronized
está básicamente bien desde el principio. Solo sobre esta base, diría quesynchronized
es más fácil (dado que desea su comportamiento) quejava.util.concurrent.locks.Lock
. par 4Hay 4 factores principales sobre por qué querrías usar
synchronized
ojava.util.concurrent.Lock
.Nota: el bloqueo sincronizado es lo que quiero decir cuando digo bloqueo intrínseco.
Cuando Java 5 salió con ReentrantLocks, demostraron tener una diferencia de rendimiento bastante notable y luego un bloqueo intrínseco. Si está buscando un mecanismo de bloqueo más rápido y está ejecutando 1.5, considere jucReentrantLock. El bloqueo intrínseco de Java 6 ahora es comparable.
jucLock tiene diferentes mecanismos para bloquear. Bloqueo interrumpible: intente bloquear hasta que se interrumpa el hilo de bloqueo; bloqueo temporizado: intente bloquear durante un cierto período de tiempo y renunciar si no tiene éxito; tryLock: intenta bloquear, si algún otro hilo está reteniendo el bloqueo. Todo esto está incluido aparte de la cerradura simple. El bloqueo intrínseco solo ofrece un bloqueo simple
fuente
Me gustaría agregar algunas cosas más sobre la respuesta de Bert F.
Locks
admite varios métodos para un control de bloqueo de grano más fino, que son más expresivos que los monitores implícitos (synchronized
bloqueos)Ventajas del bloqueo sobre la sincronización de la página de documentación
El uso de métodos o sentencias sincronizadas proporciona acceso al bloqueo de monitor implícito asociado con cada objeto, pero obliga a que todas las adquisiciones y liberaciones de bloqueos ocurran de forma estructurada en bloques.
Las implementaciones de bloqueo proporcionan una funcionalidad adicional sobre el uso de métodos y declaraciones sincronizadas al proporcionar un intento sin bloqueo para adquirir un
lock (tryLock())
, un intento de adquirir el bloqueo que se puede interrumpir (lockInterruptibly()
y un intento de adquirir el bloqueo que puede)timeout (tryLock(long, TimeUnit))
.Una clase de bloqueo también puede proporcionar un comportamiento y una semántica que es bastante diferente del bloqueo de monitor implícito, como el pedido garantizado, el uso no reentrante o la detección de punto muerto
ReentrantLock : en términos simples según mi entendimiento,
ReentrantLock
permite que un objeto vuelva a entrar de una sección crítica a otra sección crítica. Como ya tiene bloqueo para ingresar a una sección crítica, puede usar otra sección crítica en el mismo objeto utilizando el bloqueo actual.ReentrantLock
características clave según este artículoPuedes usar
ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock
para adquirir más control sobre el bloqueo granular en operaciones de lectura y escritura.Además de estos tres ReentrantLocks, Java 8 proporciona un bloqueo más
Bloqueo sellado:
Puede usar estos sellos para liberar un bloqueo o para verificar si el bloqueo sigue siendo válido. Además, los bloqueos estampados admiten otro modo de bloqueo denominado bloqueo optimista.
Eche un vistazo a este artículo sobre el uso de diferentes tipos
ReentrantLock
yStampedLock
bloqueos.fuente
La principal diferencia es la equidad, en otras palabras, ¿las solicitudes se manejan FIFO o puede haber una intrusión? La sincronización a nivel de método garantiza una asignación justa o FIFO de la cerradura. Utilizando
o
No garantiza la equidad.
Si tiene mucha contención por el bloqueo, puede encontrar fácilmente la intrusión donde las solicitudes más nuevas se bloquean y las solicitudes más antiguas se atascan. He visto casos en los que 200 hilos llegan en breve para un bloqueo y el segundo en llegar se procesó en último lugar. Esto está bien para algunas aplicaciones, pero para otras es mortal.
Consulte el libro "Concurrencia de Java en la práctica" de Brian Goetz, sección 13.3 para una discusión completa de este tema.
fuente
El libro de Brian Goetz "Java Concurrency In Practice", sección 13.3: "... Al igual que el ReentrantLock predeterminado, el bloqueo intrínseco no ofrece garantías de equidad deterministas, pero las garantías de equidad estadística de la mayoría de las implementaciones de bloqueo son lo suficientemente buenas para casi todas las situaciones ..."
fuente
Lock facilita la vida de los programadores. Aquí hay algunas situaciones que se pueden lograr fácilmente con el bloqueo.
Mientras, el bloqueo y las condiciones se basan en el mecanismo sincronizado. Por lo tanto, ciertamente puede lograr la misma funcionalidad que puede lograr con el bloqueo. Sin embargo, resolver escenarios complejos con sincronizado puede dificultar su vida y puede desviarse de resolver el problema real.
fuente
Gran diferencia entre bloqueo y sincronización:
fuente
Bloquear y sincronizar bloque sirve para el mismo propósito, pero depende del uso. Considera la parte de abajo
En el caso anterior, si un hilo ingresa al bloque de sincronización, el otro bloque también está bloqueado. Si hay varios bloques de sincronización en el mismo objeto, todos los bloques están bloqueados. En tales situaciones, java.util.concurrent.Lock se puede usar para evitar el bloqueo no deseado de bloques
fuente