Estoy tratando de entender qué hace que el bloqueo en concurrencia sea tan importante si se puede usar synchronized (this)
. En el siguiente código ficticio, puedo hacer lo siguiente:
- sincronizó todo el método o sincronizó el área vulnerable (
synchronized(this){...}
) - O bloquee el área de código vulnerable con un ReentrantLock.
Código:
private final ReentrantLock lock = new ReentrantLock();
private static List<Integer> ints;
public Integer getResult(String name) {
.
.
.
lock.lock();
try {
if (ints.size()==3) {
ints=null;
return -9;
}
for (int x=0; x<ints.size(); x++) {
System.out.println("["+name+"] "+x+"/"+ints.size()+". values >>>>"+ints.get(x));
}
} finally {
lock.unlock();
}
return random;
}
synchronized(this){synchronized(this){//some code}}
lo que no causará un bloqueo muerto. Para el bloqueo intrínseco si obtienen un monitor en un recurso y si lo desean de nuevo, pueden obtenerlo sin un bloqueo inactivo.Respuestas:
Un ReentrantLock no está estructurado , a diferencia de las
synchronized
construcciones, es decir, no necesita usar una estructura de bloque para bloquear e incluso puede mantener un bloqueo en todos los métodos. Un ejemplo:Tal flujo es imposible de representar a través de un solo monitor en una
synchronized
construcción.Aparte de eso,
ReentrantLock
admite sondeo de bloqueo y esperas de bloqueo interrumpible que admiten tiempo de espera .ReentrantLock
también tiene soporte para una política de equidad configurable , lo que permite una programación de subprocesos más flexible.ReentrantLock
También puede ser más escalable , con un rendimiento mucho mejor bajo una mayor contención. Puedes leer más sobre esto aquí .Sin embargo, esta afirmación ha sido impugnada; ver el siguiente comentario:
¿Cuándo deberías usar
ReentrantLock
s? De acuerdo con ese artículo de developerWorks ...fuente
ReentrantLockPseudoRandom
código en el enlace de Lycog está usando bloqueos nuevos e incontenidos cada invocación desetSeed
ynext
ReentrantReadWriteLock
es una cerradura especializada, mientras quesynchronized(this)
es una cerradura de uso general. Son similares pero no exactamente iguales.Tienes razón en que podrías usar en
synchronized(this)
lugar de,ReentrantReadWriteLock
pero lo contrario no siempre es cierto.Si desea comprender mejor lo que hace
ReentrantReadWriteLock
especial, busque información sobre la sincronización de subprocesos productor-consumidor.En general, puede recordar que la sincronización de todo el método y la sincronización de propósito general (usando la
synchronized
palabra clave) se pueden usar en la mayoría de las aplicaciones sin pensar demasiado en la semántica de la sincronización, pero si necesita exprimir el rendimiento de su código, es posible que necesite explore otros mecanismos de sincronización más específicos o más específicos.Por cierto, usar
synchronized(this)
, y en general bloquear usando una instancia de clase pública, puede ser problemático porque abre su código a posibles bloqueos muertos porque alguien más, a sabiendas, podría intentar bloquear su objeto en otro lugar del programa.fuente
public class MyLock { private final Object protectedLongLockingMonitor = new Object(); private long protectedLong = 0L; public void incrementProtectedLong() { synchronized(protectedLongLockingMonitor) { protectedLong++; } } }
Desde la página de documentación de Oracle sobre ReentrantLock :
Un ReentrantLock es propiedad del último hilo de bloqueo con éxito, pero aún no desbloquearlo. Volverá un bloqueo de invocación de subproceso, adquiriendo el bloqueo con éxito, cuando el bloqueo no es propiedad de otro subproceso. El método volverá inmediatamente si el hilo actual ya posee el bloqueo.
El constructor de esta clase acepta una equidad opcional. parámetro . Cuando se establece como verdadero, bajo contención, los bloqueos favorecen la concesión de acceso al hilo que más espera . De lo contrario, este bloqueo no garantiza ninguna orden de acceso en particular.
ReentrantLock clave de según este artículo
Puede usar ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock para obtener más control sobre el bloqueo granular en las operaciones de lectura y escritura.
Eche un vistazo a este artículo de Benjamen sobre el uso de diferentes tipos de ReentrantLocks
fuente
Puede usar bloqueos reentrantes con una política de equidad o tiempo de espera para evitar el hambre de hilos. Puede aplicar una política de equidad de hilo. ayudará a evitar que un hilo espere para siempre para llegar a sus recursos.
La "política de equidad" elige el siguiente hilo ejecutable para ejecutar. Se basa en la prioridad, el tiempo desde la última ejecución, bla, bla
Además, Sincronizar puede bloquear indefinidamente si no puede escapar del bloqueo. Reentrantlock puede tener un tiempo de espera establecido.
fuente
Los bloqueos sincronizados no ofrecen ningún mecanismo de cola de espera en el que, después de la ejecución de un hilo, cualquier hilo que se ejecute en paralelo pueda adquirir el bloqueo. Debido a que el subproceso que está allí en el sistema y que se ejecuta durante un período de tiempo más largo, nunca tiene la oportunidad de acceder al recurso compartido, lo que lleva al hambre.
Los bloqueos reentrantes son muy flexibles y tienen una política de equidad en la que si un hilo espera más tiempo y después de completar el hilo que se está ejecutando actualmente, podemos asegurarnos de que el hilo más largo en espera tenga la oportunidad de acceder al recurso compartido disminuyendo el rendimiento del sistema y hacerlo más lento.
fuente
Supongamos que este código se ejecuta en un hilo:
Debido a que el subproceso posee el bloqueo, permitirá que múltiples llamadas se bloqueen (), por lo que volverá a ingresar al bloqueo. Esto se puede lograr con un recuento de referencia para que no tenga que volver a adquirir el bloqueo.
fuente
Una cosa a tener en cuenta es:
el nombre ' ReentrantLock ' emite un mensaje incorrecto sobre otro mecanismo de bloqueo que no son reentrantes. Esto no es verdad. El bloqueo adquirido a través de 'sincronizado' también es reentrante en Java.
La diferencia clave es que 'sincronizado' usa bloqueo intrínseco (uno que tiene cada Objeto) mientras que Lock API no.
fuente
Creo que los métodos wait / notify / notifyAll no pertenecen a la clase Object, ya que contamina todos los objetos con métodos que rara vez se usan. Tienen mucho más sentido en una clase de bloqueo dedicada. Entonces, desde este punto de vista, quizás sea mejor usar una herramienta que esté diseñada explícitamente para el trabajo en cuestión, es decir, ReentrantLock.
fuente