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:
private ReentrantLock lock;
public void foo() {
...
lock.lock();
...
}
public void bar() {
...
lock.unlock();
...
}
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.
El constructor de esta clase acepta un parámetro opcional de equidad . Cuando se establece true
, bajo contención, los bloqueos favorecen el acceso al hilo que espera más tiempo. De lo contrario, este bloqueo no garantiza ninguna orden de acceso en particular. Los programas que usan bloqueos justos a los que acceden muchos subprocesos pueden mostrar un rendimiento general más bajo (es decir, son más lentos; a menudo mucho más lentos) que los que usan la configuración predeterminada, pero tienen variaciones más pequeñas en ocasiones para obtener bloqueos y garantizar la falta de inanición. Sin embargo, tenga en cuenta que la imparcialidad de las cerraduras no garantiza la imparcialidad de la programación de hilos. Por lo tanto, uno de los muchos subprocesos que utilizan un bloqueo equitativo puede obtenerlo varias veces seguidas, mientras que otros subprocesos activos no progresan y actualmente no mantienen el bloqueo. También tenga en cuenta que el tiempo notryLock
El método no respeta el ajuste de equidad. Tendrá éxito si el bloqueo está disponible, incluso si otros hilos están esperando.
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:
En la prueba de bloqueo reentrante, se crea un nuevo bloqueo cada vez, por lo que no hay bloqueo exclusivo y los datos resultantes no son válidos. Además, el enlace de IBM no ofrece ningún código fuente para el punto de referencia subyacente, por lo que es imposible caracterizar si la prueba incluso se realizó correctamente.
¿Cuándo deberías usar ReentrantLock
s? De acuerdo con ese artículo de developerWorks ...
La respuesta es bastante simple: úsela cuando realmente necesite algo que no proporciona synchronized
, como esperas de bloqueo programadas, esperas de bloqueo interrumpibles, bloqueos sin estructura de bloque, variables de condición múltiple o sondeo de bloqueo. ReentrantLock
también tiene beneficios de escalabilidad, y debe usarlo si realmente tiene una situación que exhibe una alta contención, pero recuerde que la gran mayoría de los synchronized
bloques casi nunca exhiben ninguna contención, y mucho menos una alta contención. Aconsejaría desarrollar con sincronización hasta que la sincronización haya demostrado ser inadecuada, en lugar de simplemente asumir que "el rendimiento será mejor" si usaReentrantLock
. Recuerde, estas son herramientas avanzadas para usuarios avanzados. (Y los usuarios verdaderamente avanzados tienden a preferir las herramientas más simples que pueden encontrar hasta que estén convencidos de que las herramientas simples son inadecuadas). Como siempre, primero haga las cosas bien y luego se preocupe si tiene que hacerlo más rápido o no.