Grundlegendes zu java.lang.Thread.State: WAITING (Parken)

88

Erstens, eine wirklich dumme Frage, ich habe mich nur gefragt, was das wartende "Parken" bedeutet. Wartet der Thread darauf, geparkt zu werden, oder wurde er gerade geparkt und befindet sich daher im Wartezustand? Und wenn dieses Parken passiert, wie viel CPU- / Speicherressourcen werden verbraucht? Was ist der Zweck, einen Thread zu parken?

Zweitens, indem Sie sich die Parkmethode in der Java-Thread-API ansehen

Deaktiviert den aktuellen Thread für Thread-Planungszwecke, sofern die Genehmigung nicht verfügbar ist.

Wenn die Genehmigung verfügbar ist, wird sie verbraucht und der Anruf wird sofort zurückgegeben. Andernfalls wird der aktuelle Thread für Thread-Planungszwecke deaktiviert und ruht, bis eines von drei Dingen passiert .....

Englisch ist nicht meine Hauptsprache, daher habe ich einige Schwierigkeiten zu verstehen, dass ich "Erlaubnis" als eine Art "Erlaubnis zum Parken des Threads" beabsichtigte, also die folgenden Fragen:

  • Was bedeutet das, was ist "Erlaubnis" und wer und wie prüft diese Erlaubnis?
  • Was bedeutet das: "Wenn eine Genehmigung verfügbar ist, wird sie verbraucht", wird sie "geparkt"?
  • Wenn der zweite Punkt zutrifft, was ist dann der Unterschied zwischen "Parken" und "Ruhen"? Wenn ich eine Erlaubnis habe, kann ich sie für immer parken und wenn nicht, kann ich sie "ruhend" machen?

Vielen Dank

Leonardo
quelle

Antworten:

35

Erlaubnis bedeutet eine Erlaubnis, die Ausführung fortzusetzen. Parken bedeutet, die Ausführung auszusetzen, bis eine Genehmigung vorliegt.

Im Gegensatz zu Semaphoreden Genehmigungen sind Genehmigungen von LockSupportThreads zugeordnet (dh die Erlaubnis wird einem bestimmten Thread erteilt) und sammeln sich nicht an (dh es kann nur eine Erlaubnis pro Thread geben, wenn der Thread die Erlaubnis verbraucht, verschwindet sie).

Sie können einem Thread eine Erlaubnis geben, indem Sie ihn aufrufen unpark(). Ein Thread kann seine Ausführung durch Aufrufen aussetzen, bis die Genehmigung verfügbar ist (oder der Thread unterbrochen wird oder das Zeitlimit abgelaufen ist usw.) park(). Wenn eine Genehmigung verfügbar ist, verbraucht der geparkte Thread diese und beendet eine park()Methode.

axtavt
quelle
2
Wenn Thread A für Thread B "Parken" aufruft, aber eine Genehmigung verfügbar ist, die "B kann nicht geparkt werden" lautet, kehrt der von A getätigte Anruf einfach zurück und B wird nicht geparkt. Andernfalls muss B gehorchen, wenn keine Genehmigung vorliegt. Bedeutet das Warten (Parken) also "A versucht mich zu parken, weil ich keine Erlaubnis habe, aber ich kann das jetzt nicht tun, also blockiere ich auch A"? Entschuldigung für diesen langen Satz. Ich nehme an, dieses Warten ist ziemlich ressourcenintensiv. Ich frage mich immer noch, wer die ganze Genehmigungssache verwaltet. Wer / was entscheidet, dass einige Threads eine Erlaubnis haben, andere nicht.
Leonardo
2
@Leonardo: Ein Thread kann sich nur selbst parken, es gibt keine Möglichkeit, andere Threads zu parken. Aufrufen park()bedeutet also "Ich möchte meine Ausführung unterbrechen, bis mir ein anderer Thread durch Aufrufen eine Erlaubnis erteilt unpark()".
Axtavt
Ein Thread kann also keine anderen Threads parken, kann aber von anderen Threads nicht geparkt werden? Ist das korrekt ? Wann findet das Parken statt? Vielleicht hat ein Thread im Moment keine Aufgabe zu erledigen, und es kann überprüft werden, indem ständig nach seiner Erlaubnis gesucht wird? Dies eignet sich beispielsweise gut für Daemon-Threads.
Leonardo
Das Warten (Parken) bedeutet auch, dass es darauf wartet, geparkt zu werden, oder dass es nach dem Parken in einem Wartezustand ist? Entschuldigung, ich weiß, dass dies eine dumme Frage ist :-)
Leonardo
3
@ Leonardo: Es bedeutet einen Wartezustand nach dem Parken.
Axtavt
11

Gemäß der Java- Thread- Statusdokumentation kann ein Thread aus drei Gründen in den Status WARTEN wechseln:

  1. Object.wait ohne Timeout
  2. Thread.join ohne Zeitüberschreitung
  3. LockSupport.park

Wenn Sie eine Parkmethode für einen Thread aufrufen, wird der Thread für Thread-Planungszwecke deaktiviert, sofern die Genehmigung nicht verfügbar ist. Sie können die Methode unpark aufrufen, um die Berechtigung für den angegebenen Thread verfügbar zu machen, sofern diese noch nicht verfügbar war.

Wenn sich Ihr Thread von LockSupport.park im WAITING-Modus befindet, wird er als WAITING (Parken) angezeigt.

Bitte beachten Sie, dass Sie park nur für den aktuellen Thread aufrufen können. Dies ist ein sehr hilfreicher Mechanismus zur Implementierung des Producer-Consumer-Design-Musters.

Badal
quelle
3

Aus der Klassenbeschreibung (oben im LockSupport-Javadoc ), in der die Genehmigung beschrieben wird:

Diese Klasse ordnet jedem Thread, der sie verwendet, eine Erlaubnis zu (im Sinne der Semaphore-Klasse). Ein Anruf zum Parken wird sofort zurückgegeben, wenn die Genehmigung verfügbar ist, wobei [die Genehmigung] verbraucht wird. Andernfalls kann [der Anruf zum Parken] blockiert werden. Ein Aufruf zum Entparken stellt die Genehmigung zur Verfügung, sofern sie noch nicht verfügbar war. (Anders als bei Semaphoren sammeln sich jedoch keine Genehmigungen an. Es gibt höchstens eine.)

(Ich habe den [Text] erweitert , um das Lesen für nicht englischsprachige Personen zu erleichtern.)

Hoffentlich kann jemand mit einem tieferen Verständnis darauf näher eingehen. Siehe die Antwort von axtavt.

Als letzte Anmerkung ein letztes Zitat aus dem Javadoc:

Diese Methoden dienen als Tools zum Erstellen von Synchronisierungsdienstprogrammen auf höherer Ebene und sind für die meisten Anwendungen zur Steuerung der Parallelität an sich nicht nützlich.

Charles Goodwin
quelle
3

Der Teil, der mich dazu brachte, diese Frage erneut zu beantworten, die ich beim Lesen der Dokumentation nicht umgehen konnte, war:

Wenn die Genehmigung verfügbar ist, wird sie verbraucht und der Anruf wird sofort zurückgegeben ...

Also, wenn die Genehmigung "verfügbar" ist, wer und wie stellt sie zur Verfügung, damit sie sofort verbraucht werden kann? Das war irgendwie trivial herauszufinden:

public static void main(String[] args) {

    Thread parkingThread = new Thread(() -> {
        System.out.println("Will go to sleep...");
        sleepTwoSeconds();
        System.out.println("Parking...");
        // this call will return immediately since we have called  LockSupport::unpark
        // before this method is getting called, making the permit available
        LockSupport.park();
        System.out.println("After parking...");
    });

    parkingThread.start();

    // hopefully this 1 second is enough for "parkingThread" to start
    // _before_ we call un-park
    sleepOneSecond();
    System.out.println("Un-parking...");
    // making the permit available while the thread is running and has not yet
    // taken this permit, thus "LockSupport.park" will return immediately
    LockSupport.unpark(parkingThread);

}

private static void sleepTwoSeconds() {
    try {
        Thread.sleep(1000 * 2);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

private static void sleepOneSecond() {
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}    

Der Code spricht für sich selbst, der threadläuft, wird aber noch nicht aufgerufen LockSupport.park, während ein anderer Thread ihn aufruft LockSupport.unpark- wodurch die Erlaubnis verfügbar wird. Danach rufen wir an LockSupport.parkund das kehrt sofort zurück, da die Genehmigung verfügbar ist.

Sobald man darüber nachdenkt, ist dies ein bisschen gefährlich, wenn Sie Ihre Fäden zu einem gewissen Code setzen Sie nicht kontrollieren , und dass Code Anrufe , LockSupport.unparkwährend Sie parkdanach - es könnte nicht funktionieren.

Eugene
quelle
Sehr guter Punkt, ich hätte gedacht, dass eine Erlaubnis, Aktivität zu geben - dh unpark () aufzurufen - nur relevant ist, wenn ein Thread geparkt wird.
Alfred Xiao
@ AlfredXiao stimmte zu, das hat mich auch überrascht, aber es macht irgendwie Sinn, denke ich.
Eugene
1

So wie ich es verstehe, ist die "Erlaubnis" nur ein Objekt, das darstellt, ob ein Thread "entparkt" werden kann oder nicht. Und dies wird vom Thread selbst überprüft (oder de JRE, wenn Sie versuchen, einen Thread zu parken). Das "verbraucht" -Ding, ich verstehe, dass die Erlaubnis verschwindet und der Thread nicht deaktiviert wird.

Ich denke, Sie sollten ein bisschen mehr über Multithreading lernen. Stellen Sie sich das als Spender mit Objekten vor, die als "Erlaubnis" bezeichnet werden. Sie weisen einen Thread an, zu parken, und der Thread überprüft den Spender. Wenn es eine "Erlaubnis" gibt, nimmt der Thread sie und geht (ohne Park). Wenn sich im Spender keine "Erlaubnis" befindet, wird der Thread geparkt, bis eine "Erlaubnis" verfügbar ist (und Sie können mit eine "Erlaubnis" in den Spender legen unpark.

Was die CPU- / Speichernutzung betrifft, denke ich, dass dies vom Betriebssystem usw. abhängt.

Vic
quelle