Quelle est la différence entre l'état du thread WAIT et l'état du thread BLOCKED?
La documentation Thread.State :
Bloqué
Un thread bloqué dans l'attente d'un verrouillage du moniteur se trouve dans cet état.Attendre
Un thread qui attend indéfiniment qu'un autre thread effectue une action particulière est dans cet état
ne m'explique pas la différence.
Un thread passe à l'état d'attente une fois qu'il a appelé wait()
sur un objet. Cela s'appelle Waiting State . Une fois qu'un thread a atteint l'état d'attente, il doit attendre qu'un autre thread notify()
ou notifyAll()
sur l'objet.
Une fois que ce thread est notifié, il ne sera pas exécutable. Il se peut que d’autres threads soient également notifiés (avec notifyAll()
) ou que le premier thread n’ait pas terminé son travail. Il est donc toujours bloqué tant qu’il n’a pas eu sa chance. Ceci s'appelle Bloqué Etat.
Une fois que les autres threads sont partis et qu’il a cette chance, il passe à l’état Runnable après qu’il constitue un travail de ramassage éligible basé sur le mécanisme de thread JVM et passe à l’état d’exécution.
La différence est relativement simple.
Dans l'état BLOCKED
, un thread est sur le point d'entrer un bloc synchronized
, mais un autre thread est en cours d'exécution dans un bloc synchronized
sur le même objet. Le premier thread doit ensuite attendre que le second thread quitte son bloc.
Dans l'état WAITING
, un thread attend un signal d'un autre thread. Cela se produit généralement en appelant Object.wait()
ou Thread.join()
. Le thread restera alors dans cet état jusqu'à ce qu'un autre thread appelle Object.notify()
ou meure.
La différence importante entre les états bloqué et d'attente est l'impact sur le planificateur. Un thread dans un état bloqué fait partie d'un groupe d'attente en concurrence pour un verrou; ce thread compte toujours comme quelque chose que l'ordonnanceur a besoin de gérer, éventuellement pris en compte dans les décisions de l'ordonnanceur concernant le temps imparti aux threads en cours d'exécution.
Une fois qu'un thread est dans l'état d'attente, le stress qu'il impose au système est minimisé et le planificateur n'a pas à s'en soucier. Il reste en veille jusqu'à ce qu'il reçoive une notification. Hormis le fait qu'il occupe un thread OS, il est totalement hors-jeu.
C’est pourquoi utiliser notifyAll n’est pas idéal, cela provoque un tas de threads qui étaient auparavant en sommeil et qui n’engendrent aucune charge sur le système, mais la plupart d’entre eux se bloqueront jusqu’à ce qu’ils puissent obtenir le verrou, trouver la condition qu’ils sont attendre n'est pas vrai, et recommencez. Il serait préférable de ne notifier que les threads qui ont une chance de progresser.
(Utiliser ReentrantLock au lieu de verrous intrinsèques vous permet d’avoir plusieurs conditions pour un verrou. Vous pouvez ainsi vous assurer que le thread notifié est en attente d’une condition particulière, ce qui évite le bogue de notification perdue dans le cas où un thread serait averti. quelque chose sur lequel il ne peut agir.)
Perspective simplifiée pour interpréter les vidages de threads:
Bloqué: votre thread est en état d'exécution du cycle de vie du thread et tente d'obtenir le verrouillage d'objet . Wait - Votre thread est en attente du cycle de vie du thread et attend le signal de notification pour qu'il soit en état d'exécution.
voir cet exemple:
démonstration des états de fil.
/*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();
}
}
}
}