Unterschied zwischen den Thread-Zuständen WAIT und BLOCKED

101

Was ist der Unterschied zwischen dem Thread-Status WAIT und dem Thread-Status BLOCKED?

Die Thread.State-Dokumentation :

Blockiert
Ein Thread, der blockiert ist und auf eine Monitorsperre wartet, befindet sich in diesem Status.

Warten
Ein Thread, der auf unbestimmte Zeit darauf wartet, dass ein anderer Thread eine bestimmte Aktion ausführt, befindet sich in diesem Status

erklärt mir den Unterschied nicht.

Mehr als fünf
quelle
Überprüfen Sie die Antwort in diesem Thread stackoverflow.com/questions/2534147/java-thread-wait-blocked auch dieser Link kann weitere Erläuterungen
Abdul
@Abdul Der Geekexplains-Link besagt, dass ein Thread durch Aufrufen von Object.wait () in einen blockierten Zustand versetzt werden kann, was nicht korrekt ist, oder?
Mehr als fünf
Laut Oracle Docs docs.oracle.com/javase/6/docs/api/java/lang/… : Ein Thread befindet sich im Wartezustand, da eine der folgenden Methoden aufgerufen wird: Object.wait ohne Zeitüberschreitung, Thread.join ohne Zeitüberschreitung, LockSupport.park
Abdul
Ich denke, die Antwort von @ Flavio ist etwas besser als die von Ankit, falls Sie eine Änderung in Betracht ziehen sollten.
Grau

Antworten:

79

Ein Thread wartet, sobald er wait()ein Objekt aufruft . Dies wird als Wartezustand bezeichnet . Sobald ein Thread den Wartezustand erreicht, muss er warten, bis ein anderer Thread notify()oder notifyAll()das Objekt aufgerufen wird.

Sobald dieser Thread benachrichtigt wurde, kann er nicht mehr ausgeführt werden. Es kann sein, dass andere Threads ebenfalls benachrichtigt werden (using notifyAll()) oder der erste Thread seine Arbeit noch nicht beendet hat, sodass er immer noch blockiert ist, bis er seine Chance bekommt. Dies wird als blockierter Zustand bezeichnet. Ein blockierter Status tritt immer dann auf, wenn ein Thread versucht, eine Sperre für ein Objekt zu erlangen, und ein anderer Thread die Sperre bereits hält.

Sobald andere Threads abgereist sind und diese Thread-Chance besteht, wechselt sie in den Status "Ausführbar". Danach ist sie berechtigt, Arbeiten basierend auf dem JVM-Threading-Mechanismus aufzunehmen, und wechselt in den Status "Ausführen".

Ankit Bansal
quelle
2
Sie haben es viel besser erklärt, weil Sie die Reihenfolge erklärt haben, in der ein Thread diese beiden Zustände erreicht, was es klarer macht, als nur jeden der beiden Zustände isoliert zu erklären (was durch die Antwort von "More Than Five"
Kumar Manish
7
Für alle, die sich fragen, warum die meisten (alle?) Der im Web gefundenen Zustandsdiagramme, die notify () / notifyAll () ergeben, zu RUNNABLE statt BLOCKED führen: stackoverflow.com/questions/28378592/…
Niklas Peter
Angenommen, es gibt nur einen Thread und es wurde einige Zeit in Millis gewartet. Ist es möglich, dass ein Thread direkt vom Wartezustand in den ausführbaren Zustand wechselt? da hier kein anderer thread sperrt da nur single threaded?
Kanagavelu Sugumar
Es gibt eine Wartezeitmethode, die nach Ablauf der Zeit wieder in den ausführbaren Zustand zurückkehrt. Wenn jedoch keine Zeit angegeben ist, wird gewartet, bis ein anderer Thread benachrichtigt oder der Thread unterbrochen wird.
Ankit Bansal
2
Ihre Antwort ist gut, aber es erklärt nicht ganz, dass Sie jederzeit in einen blockierten Zustand wechseln können, wenn Sie versuchen, eine Sperre zu erlangen. Es muss nichts mit Signal / Benachrichtigung zu tun haben.
Grau
90

Der Unterschied ist relativ einfach.

In diesem BLOCKEDZustand ist ein Thread im Begriff, einen synchronizedBlock einzugeben , aber es wird derzeit ein anderer Thread in einem synchronizedBlock für dasselbe Objekt ausgeführt. Der erste Thread muss dann warten, bis der zweite Thread seinen Block verlassen hat.

In diesem WAITINGZustand wartet ein Thread auf ein Signal von einem anderen Thread. Dies geschieht normalerweise durch Aufrufen von Object.wait()oder Thread.join(). Der Thread bleibt dann in diesem Zustand, bis ein anderer Thread aufruft Object.notify()oder stirbt.

Flavio
quelle
2
Ist es richtig zu sagen, dass nur ein Thread selbst ihn warten lassen kann? Kann Thread-B Thread-A jemals in den WAIT-Zustand versetzen?
Mehr als fünf
1
Sie verwenden selten Object.wait()direkt, aber Sie landen im WAITINGStatus, indem Sie auch die übergeordneten Parallelitätskonstrukte verwenden - wie Sperren, Blockierungswarteschlangen usw. Im Großen und Ganzen, wenn zwei Threads koordiniert werden müssen.
Flavio
1
Aus persönlicher Erfahrung sind Threads, die auf E / A warten (z. B. Lesen aus einem Socket), in RUNNINGStatus.
Flavio
4
In Java8 doc for Thread.Stateheißt es: "... Diese Zustände sind Zustände der virtuellen Maschine, die keine Betriebssystem-Thread-Zustände widerspiegeln." Mit anderen Worten, die JVM kümmert sich nicht um den Unterschied zwischen einem Thread, in dem Java-Code ausgeführt wird, einem Thread, der auf die Rückkehr eines Systemaufrufs wartet, oder einem Thread, der auf eine Zeitscheibe wartet. Das ist alles genau RUNNABLEso, wie es die JVM betrifft.
Solomon Slow
3
Es kann hilfreich sein, hinzuzufügen, dass ein Thread, wenn er aus dem WAITINGStatus wechselt, zuerst in den BLOCKEDStatus wechseln muss, bis er die Sperre für das Objekt erhalten kann, auf das er gewartet hat.
Grau
21

Der wichtige Unterschied zwischen dem blockierten und dem Wartezustand ist die Auswirkung auf den Scheduler. Ein Thread in einem blockierten Zustand kämpft um eine Sperre. Dieser Thread zählt immer noch als etwas, das der Scheduler warten muss, und wird möglicherweise in die Entscheidungen des Schedulers einbezogen, wie viel Zeit für laufende Threads zur Verfügung steht (damit die Threads, die die Sperre blockieren, eine Chance erhalten).

Sobald sich ein Thread im Wartezustand befindet, wird die Belastung des Systems minimiert, und der Scheduler muss sich keine Sorgen mehr machen. Es wird ruhend, bis es eine Benachrichtigung erhält. Abgesehen von der Tatsache, dass ein Betriebssystem-Thread besetzt bleibt, ist es völlig aus dem Spiel.

Aus diesem Grund ist die Verwendung von notifyAll weniger als ideal. Es führt dazu, dass eine Reihe von Threads, die zuvor glücklich ruhten und das System nicht belasteten, aufgeweckt wurden. Die meisten von ihnen blockieren, bis sie die Sperre erlangen und den Zustand finden, in dem sie sich befinden Warten ist nicht wahr, und kehren Sie zum Warten zurück. Es wäre vorzuziehen, nur diejenigen Threads zu benachrichtigen, die eine Chance auf Fortschritte haben.

(Wenn Sie ReentrantLock anstelle von intrinsischen Sperren verwenden, können Sie mehrere Bedingungen für eine Sperre festlegen, sodass Sie sicherstellen können, dass der benachrichtigte Thread auf eine bestimmte Bedingung wartet, und den Fehler bei der Benachrichtigung über verlorene Benachrichtigungen vermeiden, wenn ein Thread benachrichtigt wird etwas, auf das es nicht einwirken kann.)

Nathan Hughes
quelle
Liegt das daran, dass andere Threads dafür verantwortlich sind, notify () für das Monitorobjekt aufzurufen?
Berimbolo
@berimbolo: Ich verstehe nicht, was Sie fragen
Nathan Hughes
Es war im Hinblick darauf, warum ein wartender Thread nichts ist, worüber sich der Scheduler Sorgen machen muss. Ich habe mich gefragt, ob das daran liegt, dass ein anderer Thread für den Aufruf von notify verantwortlich ist, wenn er wartet.
Berimbolo
@berimbolo: Der wartende Thread wird schließlich durch eine Benachrichtigung geweckt. Der Scheduler würde entscheiden, welcher wartende Thread benachrichtigt wird.
Nathan Hughes
zählt etwas, du sagst Spin-Lock, BLOCKED bedeutet nicht, dass es Spin-Lock ist
Frank Zhang
16

Vereinfachte Perspektive für die Interpretation von Thread-Dumps:

  • WARTEN - Ich warte darauf, etwas Arbeit zu bekommen, also bin ich gerade untätig.
  • BLOCKED - Ich bin damit beschäftigt, die Arbeit zu erledigen, aber ein anderer Thread steht mir im Weg, also bin ich gerade untätig.
  • RUNNABLE ... (native Methode) - Ich habe aufgerufen, einen nativen Code (der noch nicht fertig ist) auszuführen, was die JVM betrifft. Sie sind RUNNABLE und können keine weiteren Informationen geben. Ein häufiges Beispiel wäre eine in C codierte native Socket-Listener-Methode, die tatsächlich auf das Eintreffen von Datenverkehr wartet. Ich bin also gerade inaktiv. In dieser Situation kann dies als eine besondere Art von WARTEN angesehen werden, da wir eigentlich gar nicht LAUFEN (kein CPU-Brennvorgang), aber Sie müssten einen Betriebssystem-Thread-Dump anstelle eines Java-Thread-Dumps verwenden, um dies zu sehen.
Alter Mann
quelle
1
Ich mag deine Erklärung. Genau das versuche ich gerade bei der Analyse von Thread-Dumps zu tun :)
Sridhar Sarnobat
@ MuhammadGelbana Ja, du hast recht, ich habe den Kommentar gelöscht.
Eric Wang
1
Dein RUNNABLEist nicht ganz richtig. Es könnte sich in der Java-Ausführungswarteschlange befinden, aber nicht ausgeführt werden, oder es könnte Java-Code ausführen. Es muss nicht in die Heimat rufen.
Grau
1

Blockiert - Ihr Thread befindet sich im ausführbaren Zustand des Thread-Lebenszyklus und versucht, eine Objektsperre zu erhalten. Warten - Ihr Thread befindet sich im Wartezustand des Thread-Lebenszyklus und wartet darauf, dass das Benachrichtigungssignal in den ausführbaren Zustand des Threads gelangt.

Prakash Bisht
quelle
-1

siehe dieses Beispiel:

Demonstration von Thread-Zuständen.

/*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
quelle
Vielen Dank für den Code, aber ich möchte lieber, dass Sie eine Textantwort haben und dann einen kleinen Codeblock anzeigen.
Grau