¿Por qué usar un ReentrantLock si se puede usar sincronizado(esto)?


Estoy tratando de entender qué hace que el bloqueo en concurrencia sea tan importante si se puede usar synchronized (this). En el código ficticio a continuación, puedo hacer cualquiera de los dos:

  1. sincronizado todo el método o sincronizar el área vulnerable (sincronizado(esto){...})
  2. 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;
}
Author: rouble, 2012-08-06

5 answers

Un ReentrantLock es no estructurado, a diferencia de las construcciones synchronized i es decir, no necesita usar una estructura de bloques 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 construcción synchronized.


Aparte de eso, ReentrantLock soporta lock polling y interruptible lock waits que soporta time-out. ReentrantLock también tiene soporte para configurable política de equidad , lo que permite una programación de subprocesos más flexible.

El constructor de esta clase acepta un parámetro opcional fairness. Cuando se establece true, bajo contención, los bloqueos favorecen la concesión de acceso al hilo de espera más largo. De lo contrario, este bloqueo no garantiza ningún orden de acceso en particular. Los programas que usan bloqueos justos a los que se accede por muchos hilos pueden mostrar un rendimiento general más bajo (es decir, son más lentos; a menudo mucho más lentos) que los que usan el valor predeterminado ajuste, pero tienen variaciones más pequeñas en los tiempos para obtener bloqueos y garantizar la falta de inanición. Sin embargo, tenga en cuenta que la imparcialidad de los bloqueos no garantiza la imparcialidad de la programación de subprocesos. Por lo tanto, uno de los muchos hilos que usan un bloqueo justo puede obtenerlo varias veces en sucesión mientras que otros hilos activos no están progresando y no están sosteniendo el bloqueo. También tenga en cuenta que el método untimed tryLock no respeta la configuración de equidad. Tendrá éxito si el bloqueo está disponible incluso si otros hilos son espera.


ReentrantLock may also be más escalable, rendimiento mucho mejor bajo mayor contención. Puedes leer más sobre esto aquí.

Esta afirmación ha sido impugnada, sin embargo; véase el siguiente comentario: {[18]]}

En la prueba de bloqueo de reentrada, 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 IBM link no ofrece código fuente para el subyacente benchmark por lo que es imposible caracterizar si la prueba se realizó correctamente.


¿Cuándo debe usar ReentrantLock s? Según ese artículo de developerWorks...

La respuesta es bastante simple use úsela cuando realmente necesite algo que proporcione que synchronized no, como espera de bloqueo cronometrado, espera de bloqueo interrumpible, bloqueos no estructurados en bloques, múltiples variables de condición 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 bloques synchronized casi nunca exhiben ninguna contención, y mucho menos una alta contención. Yo recomendarí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 usa ReentrantLock. 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 convencido de que las herramientas simples son inadecuadas. Como siempre, haz lo correcto primero, y luego preocúpate de si tienes que hacerlo más rápido o no.

 391
Author: oldrinb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-07-09 16:03:50

Un bloqueo de reentrada permitirá al titular del bloqueo ingresar bloques de código incluso después de haber obtenido el bloqueo ingresando otros bloques de código. Un bloqueo no reentrante tendría el bloque de soporte de bloqueo sobre sí mismo, ya que tendría que liberar el bloqueo que obtuvo de otro bloque de código para volver a obtener ese mismo bloqueo para ingresar al bloqueo anidado que requiere bloque de código

 public synchronized void functionOne() {

 // do something

 functionTwo();

 // do something else

 // redundant, but permitted...
 synchronized(this) {
 // do more stuff
 } 
 }

 public synchronized void functionTwo() {
 // do even more stuff!
 }

Las capacidades extendidas de reentrant lock incluyen: -

  1. La capacidad de tener más de una condición variable por monitor. Los monitores que usan la palabra clave sincronizada solo pueden tener uno. Esto significa que los bloqueos de reentrada admiten más de una cola wait () / notify ().
  2. La capacidad de hacer el bloqueo "justo". "las cerraduras [justas] favorecen el acceso al hilo de mayor espera. De lo contrario, este bloqueo no garantiza ningún orden de acceso en particular."Los bloques sincronizados son injustos.
  3. La capacidad de comprobar si el bloqueo está retenido.
  4. La capacidad de obtener la lista de hilos esperando en el bloqueo.

Las desventajas de los bloqueos de reentrada son: -

Necesita agregar la instrucción import. Necesidad de envolver las adquisiciones de bloqueo en un bloque try/finally. Esto lo hace más feo que la palabra clave sincronizada. La palabra clave sincronizada se puede poner en definiciones de métodos, lo que evita la necesidad de un bloque que reduce el anidamiento.

Cuándo usar: -

  1. ReentrantLock podría ser más adecuado si necesita implementar un subproceso que atraviesa una lista vinculada, bloqueando el siguiente nodo y luego desbloquear el nodo actual.
  2. La palabra clave sincronizada es apta en situaciones como el endurecimiento de bloqueo, proporciona giro adaptativo,bloqueo sesgado y el potencial de elisión de bloqueo a través del análisis de escape. Esas optimizaciones no están implementadas actualmente para ReentrantLock.

Para más información .

 17
Author: Akash5288,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-23 06:28:15

ReentrantReadWriteLock es una cerradura especializada mientras que synchronized(this) es una cerradura de propósito general. Son similares pero no del todo iguales.

Tienes razón en que podrías usar synchronized(this) en lugar de ReentrantReadWriteLock pero lo contrario no siempre es cierto.

Si desea comprender mejor lo que hace que ReentrantReadWriteLock sea 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 (utilizando la palabra clave synchronized) se puede usar en la mayoría de las aplicaciones sin pensar demasiado sobre la semántica de la sincronización, pero si necesita exprimir el rendimiento de su código, puede que necesite explorar otros mecanismos de sincronización más precisos o de propósito especial.

Por cierto, usar synchronized(this) - y en general bloquear usando una instancia de clase pública-puede ser problemático porque abre tu código a posibles bloqueos muertos porque alguien más no lo intentaría a sabiendas para bloquear su objeto en otro lugar del programa.

 12
Author: Mike Dinescu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-12 16:21:54

De la página de documentación de oracle sobre ReentrantLock :

Un bloqueo de exclusión mutua reentrante con el mismo comportamiento básico y semántica que el bloqueo de monitor implícito al que se accede utilizando métodos y sentencias sincronizados, pero con capacidades extendidas.

  1. Un ReentrantLock es propiedad del hilo último bloqueo correctamente, pero aún no desbloqueo. Un hilo que invoca el bloqueo regresará, adquiriendo con éxito el bloqueo, cuando el bloqueo no es propiedad de otro hilo. El método regresará inmediatamente si el hilo actual ya posee el bloqueo.

  2. El constructor de esta clase acepta un parámetro opcional fairness. Cuando se establece true, bajo contención, los bloqueos favorecen la concesión de acceso al hilo de mayor espera. De lo contrario, este bloqueo no garantiza ningún orden de acceso en particular.

ReentrantLock características clave según esto artículo

  1. Capacidad para bloquear de forma interrumpible.
  2. Capacidad de tiempo de espera mientras se espera el bloqueo.
  3. Poder para crear fair lock.
  4. API para obtener la lista de subprocesos en espera para el bloqueo.
  5. Flexibilidad para intentar bloquear sin bloquear.

Puede usar ReentrantReadWriteLock.readLock, ReentrantReadWriteLock.writeLock para adquirir más control sobre el bloqueo granular en operaciones de lectura y escritura.

Echa un vistazo a esto artículo de Benjamín sobre el uso de diferentes tipos de Reentrantes

 6
Author: Ravindra babu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-07 08:27:02

Puede usar bloqueos de reentrada con una política de equidad o tiempo de espera para evitar la inanición del hilo. Puede aplicar una política de equidad de hilo. ayudará a evitar que un hilo espere para siempre para llegar a sus recursos.

private final ReentrantLock lock = new ReentrantLock(true);
//the param true turns on the fairness policy. 

La "política de equidad" elige el siguiente hilo ejecutable a ejecutar. Se basa en la prioridad, el tiempo desde la última ejecución, bla bla

También, Sincronizar puede bloquear indefinidamente si no puede escapar del bloque. Reentrantlock puede tener tiempo de espera establecido.

 0
Author: j2emanue,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-18 18:59:15