Differenza tra gli stati del thread WAIT e BLOCKED


101

Qual è la differenza tra lo stato del thread WAIT e lo stato del thread BLOCKED?

La documentazione di Thread.State :

Bloccato
Un thread bloccato in attesa di un blocco del monitor si trova in questo stato.

In attesa
Un thread che attende indefinitamente che un altro thread esegua una particolare azione si trova in questo stato

non mi spiega la differenza.


controlla la risposta in questo thread stackoverflow.com/questions/2534147/java-thread-wait-blocked anche questo link può fornire ulteriori chiarimenti geekexplains.blogspot.cz/2008/07/…
Abdul

@Abdul il link geekexplains dice che un thread può entrare in uno stato bloccato chiamando Object.wait () che non è corretto, vero?
Più di cinque

secondo oracle docs docs.oracle.com/javase/6/docs/api/java/lang/… : Un thread è in stato di attesa a causa della chiamata a uno dei seguenti metodi: Object.wait senza timeout, Thread.join senza timeout, LockSupport.park
Abdul

Per la cronaca, penso che la risposta di @ Flavio sia un po 'migliore di quella di Ankit nel caso tu possa considerare di cambiare.
Grey

Risposte:


80

Un thread passa allo stato di attesa una volta chiamato wait() un oggetto. Questo si chiama Waiting State. Una volta che un thread raggiunge lo stato di attesa, dovrà attendere fino a quando un altro thread non chiama notify()o notifyAll()sull'oggetto.

Una volta che questo thread viene notificato, non sarà più eseguibile. È possibile che anche altri thread ricevano una notifica (utilizzandonotifyAll() ) o il primo thread non abbia terminato il suo lavoro, quindi è ancora bloccato finché non ne ha la possibilità. Questo è chiamato stato bloccato . Uno stato Bloccato si verificherà ogni volta che un thread tenta di acquisire il blocco sull'oggetto e qualche altro thread sta già mantenendo il blocco.

Una volta che gli altri thread sono usciti e questa è la possibilità del thread, passa allo stato Runnable, dopodiché è idoneo a riprendere il lavoro in base al meccanismo di threading JVM e passa allo stato di esecuzione.


2
Lo hai spiegato molto meglio perché hai spiegato la sequenza in cui un thread raggiunge questi due stati, il che rende più chiaro che spiegare ciascuno dei due stati isolatamente (che è fatto dalla risposta di "More Than Five"
Kumar Manish

7
Per tutti coloro, che si chiedono perché la maggior parte (tutti?) Dei diagrammi di stato trovati nella dichiarazione web, che notify () / notifyAll () risulta RUNNABLE invece che BLOCKED: stackoverflow.com/questions/28378592/…
Niklas Peter

Supponiamo che ci sia un solo thread e che sia stato atteso un po 'di tempo in millisecondi; ora È possibile che un thread possa passare direttamente dallo stato di attesa allo stato eseguibile? poiché nessun altro thread prende il blocco qui poiché solo a thread singolo?
Kanagavelu Sugumar

Esiste un metodo wait (time) che tornerà allo stato eseguibile una volta trascorso il tempo. Ma se non viene specificato alcun tempo, attenderà fino a quando un altro thread notificherà o il thread verrà interrotto.
Ankit Bansal

2
La tua risposta è buona ma non spiega del tutto che puoi entrare in uno stato Bloccato ogni volta che provi ad acquisire un lucchetto. Non ha nulla a che fare con segnale / notifica.
Gray

90

La differenza è relativamente semplice.

Nello BLOCKEDstato, un thread sta per entrare in un synchronizedblocco, ma c'è un altro thread attualmente in esecuzione all'interno di un synchronizedblocco sullo stesso oggetto. Il primo thread deve quindi attendere che il secondo thread esca dal blocco.

Nello WAITINGstato, un thread attende un segnale da un altro thread. Ciò accade in genere chiamando Object.wait(), o Thread.join(). Il thread rimarrà quindi in questo stato fino a quando un altro thread non chiama Object.notify()o muore.


2
è corretto dire che solo un thread stesso può farlo andare in attesa? Il Thread-B può mai fare in modo che il Thread-A passi allo stato WAIT?
Più di cinque

1
Usi raramente Object.wait()direttamente, ma finisci nello WAITINGstato che utilizza anche i costrutti di concorrenza di più alto livello, come i blocchi, le code di blocco, ecc. In generale, ogni volta che due thread devono coordinarsi.
Flavio

1
Per esperienza personale, i thread in attesa di IO (ad esempio, la lettura da un Socket) sono nello RUNNINGstato.
Flavio

4
Il documento Java8 per Thread.Statedice: "... Questi stati sono stati della macchina virtuale che non riflettono alcuno stato del thread del sistema operativo." In altre parole, la JVM non si preoccupa della differenza tra un thread che esegue codice Java, un thread che è in attesa del ritorno di una chiamata di sistema o un thread che è in attesa di un intervallo di tempo. Questi sono tutti solo per RUNNABLEquanto riguarda la JVM.
Solomon Slow

3
Potrebbe essere carino aggiungere che quando un thread si sposta dallo WAITINGstato, deve prima passare allo BLOCKEDstato finché non può acquisire il blocco associato all'oggetto su cui era in attesa.
Grey

22

L'importante differenza tra gli stati di blocco e di attesa è l'impatto sullo scheduler. Un thread in uno stato bloccato sta contendendo un blocco; quel thread conta ancora come qualcosa che lo scheduler deve servire, possibilmente preso in considerazione nelle decisioni dello scheduler su quanto tempo dare ai thread in esecuzione (in modo che possa dare una possibilità ai thread che si bloccano sul blocco).

Una volta che un thread è in stato di attesa, lo stress che mette sul sistema viene ridotto al minimo e lo scheduler non deve preoccuparsene. Rimane inattivo fino a quando non riceve una notifica. A parte il fatto che tiene occupato un thread del sistema operativo, è completamente fuori gioco.

Questo è il motivo per cui l'utilizzo di notifyAll è tutt'altro che ideale, causa il risveglio di un gruppo di thread che prima erano felicemente dormienti senza caricare il sistema, dove la maggior parte di loro si bloccherà fino a quando non potranno acquisire il blocco, trovare la condizione in cui sono aspettare non è vero, e tornare ad aspettare. Sarebbe preferibile notificare solo quei thread che hanno la possibilità di fare progressi.

(L'utilizzo di ReentrantLock al posto dei blocchi intrinseci consente di avere più condizioni per un blocco, in modo da poter assicurarsi che il thread notificato sia uno che è in attesa di una condizione particolare, evitando il bug di notifica persa nel caso in cui un thread venga notificato per qualcosa su cui non può agire.)


È perché è responsabilità di altri thread chiamare notify () sull'oggetto monitor?
berimbolo

@berimbolo: Non capisco cosa stai chiedendo
Nathan Hughes

Riguardava il motivo per cui un thread in attesa non è qualcosa di cui lo scheduler deve preoccuparsi. Mi chiedevo se fosse perché un altro thread sarà responsabile della chiamata di notifica se è in attesa.
berimbolo

@berimbolo: il thread in attesa alla fine viene svegliato da una notifica. Lo scheduler deciderà quale thread in attesa riceve la notifica.
Nathan Hughes

conta qualcosa, stai dicendo spin-lock, dose BLOCCATA non significa che sia spin-lock
Frank Zhang

16

Prospettiva semplificata per interpretare i dump dei thread:

  • ASPETTA - Sto aspettando che mi venga dato del lavoro, quindi sono inattivo in questo momento.
  • BLOCCATO - Sono impegnato a portare a termine il lavoro, ma un altro thread mi ostacola, quindi sono inattivo in questo momento.
  • ESEGUIBILE ... (Metodo nativo) - Ho chiamato per ESEGUIRE del codice nativo (che non è ancora terminato) quindi per quanto riguarda la JVM, sei RUNNABLE e non può fornire ulteriori informazioni. Un esempio comune sarebbe un metodo listener socket nativo codificato in C che è in realtà in attesa dell'arrivo di traffico, quindi sono inattivo in questo momento. In quella situazione, questo può essere visto come un tipo speciale di WAIT in quanto non stiamo effettivamente RUNNING (nessuna bruciatura della CPU) ma dovresti usare un dump del thread del sistema operativo piuttosto che un dump del thread Java per vederlo.

1
Mi piace la tua spiegazione. Questo è esattamente quello che sto cercando di fare nell'analizzare i dump dei thread in questo momento :)
Sridhar Sarnobat

@MuhammadGelbana Sì, hai ragione, ho cancellato il commento.
Eric Wang

1
Il tuo RUNNABLEnon è del tutto corretto. Potrebbe essere nella coda di esecuzione Java ma non in esecuzione o potrebbe essere in esecuzione codice Java. Non deve essere un richiamo alla patria.
Grey

1

Bloccato: il thread è in uno stato eseguibile del ciclo di vita del thread e sta tentando di ottenere il blocco dell'oggetto. Attesa: il thread è in stato di attesa del ciclo di vita del thread e in attesa del segnale di notifica per entrare nello stato eseguibile del thread.


-1

guarda questo esempio:

dimostrazione degli stati del thread.

/*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();
        }
    }
}
}

Grazie per il codice, ma preferisco che tu abbia una risposta testuale e poi mostri un piccolo blocco di codice.
Grey
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.