Diferencia entre los estados de hilo WAIT y BLOCKED

101

¿Cuál es la diferencia entre el estado del hilo WAIT y el estado del hilo BLOQUEADO?

La documentación de Thread.State :

Bloqueado
Un subproceso que está bloqueado esperando un bloqueo de monitor se encuentra en este estado.

En espera
Un subproceso que está esperando indefinidamente a que otro subproceso realice una acción en particular se encuentra en este estado

no me explica la diferencia.

Más de cinco
fuente
verifique la respuesta en este hilo stackoverflow.com/questions/2534147/java-thread-wait-blocked también este enlace puede proporcionar más aclaraciones geekexplains.blogspot.cz/2008/07/…
Abdul
@Abdul el enlace geekexplains dice que un hilo puede entrar en un estado bloqueado llamando a Object.wait () eso no es correcto, ¿verdad?
Más de cinco
de acuerdo con oracle docs docs.oracle.com/javase/6/docs/api/java/lang/… : Un hilo está en estado de espera debido a que se llama a uno de los siguientes métodos: Object.wait sin tiempo de espera, Thread.join sin tiempo de espera, LockSupport.park
Abdul
Para que conste, creo que la respuesta de @ Flavio es un poco mejor que la de Ankit en caso de que considere cambiar.
Gray

Respuestas:

80

Un hilo pasa al estado de espera una vez que llama wait()a un objeto. Esto se llama Estado de espera . Una vez que un hilo alcanza el estado de espera, tendrá que esperar hasta que otro hilo llame notify()o notifyAll()en el objeto.

Una vez que se notifique este hilo, no se podrá ejecutar. Puede ser que otros hilos también sean notificados (usando notifyAll()) o que el primer hilo no haya terminado su trabajo, por lo que aún está bloqueado hasta que tenga su oportunidad. Esto se llama estado bloqueado . Se producirá un estado bloqueado siempre que un subproceso intente adquirir un bloqueo en un objeto y algún otro subproceso ya esté bloqueando el bloqueo.

Una vez que otros subprocesos se han ido y es esta posibilidad de subproceso, se mueve al estado Ejecutable después de que es elegible para recoger trabajo basado en el mecanismo de subprocesamiento de JVM y se mueve al estado de ejecución.

Ankit Bansal
fuente
2
Lo explicó mucho mejor porque explicó la secuencia en la que un hilo llega a esos dos estados, lo que lo hace más claro que simplemente explicar cada uno de los dos estados de forma aislada (lo que se hace con la respuesta de "Más de cinco"
Kumar Manish
7
Para todos aquellos, ¿quién se pregunta por qué la mayoría (¿todos?) De los diagramas de estado que se encuentran en el reclamo web, que notifican () / notifican a todos () dan como resultado RUNNABLE en lugar de BLOCKED: stackoverflow.com/questions/28378592/…
Niklas Peter
Suponga que solo hay un hilo y esperó algún tiempo en milis; ahora ¿Es posible que un hilo pueda pasar directamente del estado de espera al estado ejecutable? ya que ningún otro hilo se bloquea aquí ya que solo un hilo?
Kanagavelu Sugumar
Hay un método de espera (tiempo) que volverá al estado ejecutable una vez que haya transcurrido el tiempo. Pero si no se especifica ningún tiempo, esperará hasta que otro hilo lo notifique o se interrumpa el hilo.
Ankit Bansal
2
Su respuesta es buena, pero no explica del todo que puede ingresar a un estado Bloqueado cada vez que intente adquirir un bloqueo. No tiene nada que ver con la señal / notificación.
Gray
90

La diferencia es relativamente simple.

En el BLOCKEDestado, un hilo está a punto de entrar en un synchronizedbloque, pero hay otro hilo que se está ejecutando actualmente dentro de un synchronizedbloque en el mismo objeto. El primer hilo debe esperar a que el segundo hilo salga de su bloque.

En el WAITINGestado, un hilo está esperando una señal de otro hilo. Esto sucede normalmente llamando Object.wait(), o Thread.join(). El hilo permanecerá en este estado hasta que otro hilo llame Object.notify()o muera.

Flavio
fuente
2
¿Es correcto decir que solo un hilo en sí mismo puede hacer que entre en espera? ¿Puede Thread-B hacer que Thread-A pase al estado de ESPERA?
Más de cinco
1
Rara vez lo usa Object.wait()directamente, pero termina en el WAITINGestado también usando las construcciones de concurrencia de más alto nivel, como bloqueos, colas de bloqueo, etc., en términos generales, siempre que dos subprocesos tienen que coordinarse.
Flavio
1
Según la experiencia personal, los subprocesos que esperan IO (por ejemplo, la lectura de un Socket) están en RUNNINGestado.
Flavio
4
El documento Java8 para Thread.Statedice: "... Estos estados son estados de máquinas virtuales que no reflejan ningún estado de subprocesos del sistema operativo". En otras palabras, a la JVM no le importa la diferencia entre un subproceso que ejecuta código Java, un subproceso que está esperando a que regrese una llamada del sistema o un subproceso que está esperando un intervalo de tiempo. Esos son todos en lo RUNNABLEque respecta a la JVM.
Solomon Slow
3
Sería bueno agregar que cuando un hilo se mueve del WAITINGestado, primero debe ir al BLOCKEDestado hasta que pueda adquirir el bloqueo asociado con el objeto que estaba esperando.
Gray
22

La diferencia importante entre los estados bloqueado y de espera es el impacto en el planificador. Un hilo en un estado bloqueado está compitiendo por un bloqueo; ese hilo todavía cuenta como algo que el programador necesita atender, posiblemente siendo un factor en las decisiones del programador sobre cuánto tiempo dar a los hilos en ejecución (para que pueda dar una oportunidad a los hilos que bloquean el bloqueo).

Una vez que un hilo está en estado de espera, el estrés que ejerce en el sistema se minimiza y el programador no tiene que preocuparse por ello. Permanece inactivo hasta que recibe una notificación. Excepto por el hecho de que mantiene un hilo del sistema operativo ocupado, está completamente fuera de juego.

Esta es la razón por la que el uso de notifyAll es menos que ideal, hace que un grupo de subprocesos que antes estaban felizmente inactivos y sin carga en el sistema se despierten, donde la mayoría de ellos se bloquearán hasta que puedan adquirir el bloqueo, encontrar la condición en la que se encuentran. esperar no es cierto, y vuelva a esperar. Sería preferible notificar solo a aquellos hilos que tienen posibilidades de progresar.

(El uso de ReentrantLock en lugar de bloqueos intrínsecos le permite tener múltiples condiciones para un bloqueo, de modo que pueda asegurarse de que el hilo notificado sea uno que esté esperando en una condición particular, evitando el error de notificación perdida en el caso de que se notifique un hilo para algo sobre lo que no puede actuar).

Nathan Hughes
fuente
¿Es eso porque es responsabilidad de otros subprocesos llamar a notify () en el objeto de monitor?
berimbolo
@berimbolo: No entiendo lo que estás preguntando
Nathan Hughes
Fue con respecto a por qué un hilo en espera no es algo de lo que el programador deba preocuparse. Me preguntaba si eso era porque otro hilo será responsable de llamar a notificar si está esperando.
berimbolo
@berimbolo: el hilo en espera finalmente se despierta mediante una notificación. El planificador decidiría qué hilo en espera se notifica.
Nathan Hughes
cuenta algo, está diciendo bloqueo de giro, dosis BLOQUEADA no significa que sea bloqueo de giro
Frank Zhang
16

Perspectiva simplificada para interpretar volcados de hilo:

  • ESPERE - Estoy esperando que me den algo de trabajo, así que estoy inactivo ahora mismo.
  • BLOQUEADO : estoy ocupado tratando de hacer el trabajo, pero otro hilo se interpone en mi camino, así que estoy inactivo en este momento.
  • RUNNABLE ... (Native Method) - Llamé a EJECUTAR un código nativo (que aún no ha terminado) por lo que en lo que respecta a la JVM, eres RUNNABLE y no puede dar más información. Un ejemplo común sería un método de escucha de socket nativo codificado en C que en realidad está esperando que llegue el tráfico, por lo que estoy inactivo en este momento. En esa situación, esto puede verse como un tipo especial de ESPERA, ya que en realidad no estamos EN EJECUCIÓN (sin quemadura de CPU), pero tendrías que usar un volcado de subprocesos del sistema operativo en lugar de un volcado de subprocesos de Java para verlo.
tipo viejo
fuente
1
Me gusta tu explicación. Eso es exactamente lo que estoy tratando de hacer al analizar volcados de subprocesos en este momento :)
Sridhar Sarnobat
@MuhammadGelbana Sí, tienes razón, he eliminado el comentario.
Eric Wang
1
Tu RUNNABLEno está del todo bien. Podría estar en la cola de ejecución de Java pero no se está ejecutando o podría estar ejecutando código Java. No tiene por qué estar llamando a la tierra natal.
Gray
1

Bloqueado: su subproceso está en un estado ejecutable del ciclo de vida del subproceso e intenta obtener el bloqueo de objeto. Esperar: su hilo está en estado de espera del ciclo de vida del hilo y esperando que la señal de notificación entre en estado ejecutable del hilo.

Prakash Bisht
fuente
-1

mira este ejemplo:

demostración de estados de hilo.

/*NEW- thread object created, but not started.
RUNNABLE- thread is executing.
BLOCKED- waiting for monitor after calling wait() method.
WAITING- when wait() if called & waiting for notify() to be called.
  Also when join() is called.
TIMED_WAITING- when below methods are called:
 Thread.sleep
 Object.wait with timeout
 Thread.join with timeout
TERMINATED- thread returned from run() method.*/
public class ThreadBlockingState{

public static void main(String[] args) throws InterruptedException {
    Object obj= new Object();
    Object obj2 = new Object();
    Thread3 t3 = new Thread3(obj,obj2);
    Thread.sleep(1000);
    System.out.println("nm:"+t3.getName()+",state:"+t3.getState().toString()+
            ",when Wait() is called & waiting for notify() to be called.");
    Thread4 t4 = new Thread4(obj,obj2);
    Thread.sleep(3000);
    System.out.println("nm:"+t3.getName()+",state:"+t3.getState().toString()+",After calling Wait() & waiting for monitor of obj2.");
    System.out.println("nm:"+t4.getName()+",state:"+t4.getState().toString()+",when sleep() is called.");
}

}
class Thread3 extends Thread{
Object obj,obj2;
int cnt;
Thread3(Object obj,Object obj2){
    this.obj = obj;
    this.obj2 = obj2;
    this.start();
}

@Override
public void run() {
    super.run();
    synchronized (obj) {
        try {
            System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",Before Wait().");
            obj.wait();             
            System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",After Wait().");
            synchronized (obj2) {
                cnt++;
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}
class Thread4 extends Thread{
Object obj,obj2;
Thread4(Object obj,Object obj2){
    this.obj = obj;
    this.obj2 = obj2;
    this.start();
}

@Override
public void run() {
    super.run();
    synchronized (obj) {
        System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",Before notify().");
        obj.notify();
        System.out.println("nm:"+this.getName()+",state:"+this.getState().toString()+",After notify().");
    }
    synchronized (obj2) {
        try {
            Thread.sleep(15000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
}
murali
fuente
Gracias por el código, pero prefiero que tenga una respuesta textual y luego muestre un pequeño bloque de código.
Gray