Por qué la condición de bloqueo en espera debe mantener el bloqueo

Estoy en duda con eso, en lenguaje Java, necesitamos adquirir el bloqueo, antes de esperar alguna condición para ser satisfecho.

Por ejemplo, int java monitor lock:

synchronized(lock){
   System.out.println("before lock ...");
   lock.wait();
   System.out.println("after lock ...");
}

o las utilidades de concurrencia:

Lock lock = new ReentrantLock();
Condition cond = lock.newCondition();

lock.lock();
try{
     System.out.println("before condition ...");
     cond.await();
     System.out.println("after condition ...");
}catch(Exception e){
     e.printStackTrace();
}finally{
     lock.unlock();
}

Entonces, ¿por qué no podemos esperar sin mantener la cerradura?

¿Hay otros lenguajes diferentes o es solo en Java?

Espero que pueda explicar la razón después del diseño, pero no solo para la definición JAVA-SPEC.

Respuesta 1

Bueno, que estamos esperando? Estamos esperando que una condición se haga realidad. Otro hilo hará que la condición sea verdadera, luego notificará a los hilos en espera.

Antes de entrar a esperar, debemos verificar que la condición sea falsa; esta verificación y la espera deben ser atómicas , es decir, bajo la misma cerradura. De lo contrario, si ingresamos la espera mientras la condición ya es verdadera, probablemente nunca despertaremos.

Por lo tanto, es necesario que el bloqueo ya esté adquirido antes de llamarwait()

synchronized(lock)
{
    if(!condition)
        lock.wait();

Si wait()automáticamente y en silencio adquiere bloqueo, muchos errores no serán detectados.


Al despertar desde wait(), debemos verificar la condición nuevamente; no hay garantía de que la condición se haga realidad aquí (por muchas razones: despertar espurio; tiempo de espera, interrupción, múltiples camareros, múltiples condiciones)

synchronized(lock)
{
    if(!condition)
        lock.wait();
    if(!condition)   // check again
        ...

Por lo general, si la condición sigue siendo falsa, esperaremos nuevamente. Por lo tanto, el patrón típico es

    while(!condition)
        lock.wait();

Pero también hay casos en los que no queremos esperar nuevamente.


¿Podría haber casos de uso legítimos en los que la espera / notificación desnuda tenga sentido?

synchronized(lock){ lock.wait(); }

Seguro; una aplicación se puede hacer con esperar / notificar desnudo, con un comportamiento bien definido; Se puede argumentar que este es el comportamiento deseado; y esta es la mejor implementación para ese comportamiento.

Sin embargo, ese no es el patrón de uso típico, y no hay razón para tenerlo en cuenta en el diseño de la API.

Respuesta: 2

Ver el documento para la condición .

Una condición es como un grupo de espera o un conjunto de espera de un objeto y reemplaza el uso de los métodos de supervisión de objetos (esperar, notificar y notificar a todos). Las condiciones permiten que un hilo suspenda la ejecución (para "esperar") hasta que otro hilo le notifique que alguna condición de estado puede ser cierta. Una instancia de condición está intrínsecamente vinculada a un bloqueo, al igual que los métodos de supervisión de objetos requieren el bloqueo del objeto compartido para esperar o notificar. Entonces, antes de invocar a wait () en una condición, el hilo debe haber bloqueado el objeto Lock que se usa para producir la condición. Cuando se invoca el método await (), se libera el bloqueo asociado con la condición.

Respuesta: 3

Si el hilo simplemente estuviera esperando una señal para proceder, existen otros mecanismos para hacerlo. Presumiblemente, hay algún estado protegido por la cerradura en el que el hilo está esperando para ser operado y satisface alguna condición. Para proteger adecuadamente ese estado, el hilo debe tener el bloqueo antes y después de esperar la condición, por lo que tiene sentido exigir la adquisición del bloqueo.

Respuesta: 4

Tengo un algoritmo que calcula el percentil (85) con Apache Commons de una serie de valores (12 valores), para una evaluación posterior con un umbral para tomar una decisión. El resultado es similar al ...

Estoy tratando de usar java.time.LocalDate en mi aplicación de Android, sin embargo, si trato de importarlo, cualquier clase de java.time da un error de símbolo no puede resolver en Android studio 1.1 La única razón por la que ...

Utilizo las pruebas JUnit y AssertJ para mi aplicación Swing escrita en Java 8. Me gustaría probar si el valor del control deslizante cambia cuando se hace clic en un botón, pero no encontré ninguna forma de obtener un valor actual de un ...

Desarrollé y construí mi aplicación Java usando Maven. Necesito admitir Java 1.6, por lo que uso las siguientes propiedades: <maven.compiler.target> 1.6 </maven.compiler.target> <maven.compiler ...