Saltar al contenido

¿Cuál es el significado de “ReentrantLock” en Java?

Alonzo, parte de este gran staff, nos ha hecho el favor de redactar este post porque conoce a la perfección dicho tema.

Solución:

La reentrada significa que los bloqueos se adquieren por subproceso en lugar de por invocación.

Esa es una definición engañosa. Está true (más o menos), pero pierde el punto real.

Reentrada significa (en terminología general de CS / TI) que haces algo y, mientras lo sigues haciendo, lo vuelves a hacer. En el caso de las cerraduras, significa que haces algo como esto en un solo hilo:

  1. Adquirir un candado en “foo”.
  2. Hacer algo
  3. Adquirir un candado en “foo”. Tenga en cuenta que no hemos liberado el bloqueo que adquirimos previamente.
  4. Liberar bloqueo en “foo”
  5. Liberar bloqueo en “foo”

Con un mecanismo de bloqueo / bloqueo reentrante, el intento de adquirir el mismo bloqueo tendrá éxito e incrementará un contador interno que pertenece al bloqueo. El bloqueo solo se liberará cuando el titular actual del bloqueo lo haya liberado dos veces.

Aquí hay un ejemplo en Java que usa bloqueos / monitores de objetos primitivos … que son reentrantes:

Object lock = new Object();
...
synchronized (lock) 
    ...
    doSomething(lock, ...)
    ...


public void doSomething(Object lock, ...) 
    synchronized (lock) 
        ...
    

La alternativa al reentrante es el bloqueo no reentrante, donde sería un error que un subproceso intentara adquirir un bloqueo que ya tiene.

La ventaja de usar bloqueos reentrantes es que no tiene que preocuparse por la posibilidad de fallar debido a la adquisición accidental de un bloqueo que ya tiene. La desventaja es que no puede asumir que nada de lo que llame cambiará el estado de las variables que el bloqueo está diseñado para proteger. Sin embargo, eso no suele ser un problema. Los bloqueos se utilizan generalmente para proteger contra cambios de estado simultáneos realizados por otro hilos.


Entonces, ¿no necesito considerar los puntos muertos?

Si tu puedes.

Un subproceso no se interbloqueará contra sí mismo (si el bloqueo es reentrante). Sin embargo, podría obtener un interbloqueo si hay otros subprocesos que podrían tener un bloqueo en el objeto que está tratando de bloquear.

Imagina algo como esto:

function A():
   lock (X)
       B()
   unlock (X)

function B():
    A()

Ahora llamamos A. Sucede lo siguiente:

  • Introducimos A, bloqueando X
  • Entramos en B
  • Introducimos A de nuevo, bloqueando X de nuevo

Dado que nunca salimos de la primera invocación de A, X todavía está bloqueado. Esto se denomina reingreso: mientras que la función A aún no ha regresado, se vuelve a llamar a la función A. Si A se basa en alguna global, static estado, esto puede causar un ‘error de reingreso’, donde antes del static El estado se limpia desde la salida de la función, la función se ejecuta de nuevo y la mitad de los valores calculados chocan con el inicio de la segunda llamada.

En este caso, nos encontramos con un candado que ya tenemos. Si la cerradura es consciente de la reentrada, se dará cuenta de que somos el mismo hilo que ya sostiene la cerradura y nos dejará pasar. De lo contrario, quedará bloqueado para siempre: estará esperando un bloqueo que ya tiene.

en Java, lock y synchronized son conscientes de la reentrada: si un hilo mantiene un bloqueo y el hilo intenta volver a adquirir el mismo bloqueo, está permitido. Entonces, si escribimos el pseudocódigo anterior en Java, no se bloquearía.

Concurrencia de Java en los estados del libro de práctica: Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

Déjame explicarte qué significa exactamente. En primer lugar, las cerraduras intrínsecas son reentrantes por naturaleza. La forma en que se logra el reingreso es manteniendo un contador para el número de candados adquiridos y el propietario del candado. Si el recuento es 0 y no hay ningún propietario asociado, significa que ningún subproceso mantiene el bloqueo. Cuando un subproceso adquiere el bloqueo, JVM registra al propietario y establece el contador en 1. Si el mismo subproceso intenta adquirir el bloqueo nuevamente, el contador se incrementa. Y cuando el subproceso propietario sale del bloque sincronizado, el contador disminuye. Cuando el conteo llega a 0 nuevamente, se libera el bloqueo.

Un ejemplo simple sería –

public class Test 
    public synchronized void performTest() 
       //...
    


public class CustomTest extends Test 
    public synchronized void performTest() 
       //...
       super.performTest();
    

sin reingreso habría un punto muerto.

ingrese la descripción de la imagen aquí

Finalizando este artículo puedes encontrar las reseñas de otros sys admins, tú aún eres capaz insertar el tuyo si te gusta.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *