1350 Stimmen

Unterschied zwischen "wait()" vs "sleep()" in Java

Was ist der Unterschied zwischen einem wait() und sleep() in Threads?

Ist mein Verständnis richtig, dass ein wait()-ender Thread sich immer noch im Laufmodus befindet und CPU-Zyklen verwendet, während ein sleep()-ender Thread keine CPU-Zyklen verbraucht?

Warum haben wir beide wait() und sleep()?

Wie unterscheidet sich deren Implementierung auf niedrigerer Ebene?

61 Stimmen

Sehr gute Frage. Die Semantik beider ist leicht zu verwechseln.

1 Stimmen

Sehr gute Fragen, aber sie sind 2 in einem. Warum wir beide haben, ist nicht dasselbe wie wie sie auf einer niedrigeren Ebene implementiert werden können (und nicht sind!). Darauf habe ich auch geantwortet.

0 Stimmen

Angenommen ein Thread A befindet sich in einem synchronisierten Block, und während er in der CPU ist, wird dieser Thread einem anderen Thread B übergeben. In welchem Zustand wird Thread A jetzt sein? Werden die anderen Threads, die auf diesem synchronisierten Block warten, jetzt eintreten?

915voto

oxbow_lakes Punkte 131223

Eine wait kann von einem anderen Thread "aufgeweckt" werden, der notify auf dem Monitor aufruft, auf dem gewartet wird, während ein sleep dies nicht kann. Außerdem muss ein wait (und notify) in einem blockierten synchronized am Monitorobjekt erfolgen, während sleep das nicht erforderlich macht:

Object mon = ...;
synchronized (mon) {
    mon.wait();
} 

An diesem Punkt wartet der aktuell ausgeführte Thread und gibt den Monitor frei. Ein anderer Thread kann das Folgende tun

synchronized (mon) { mon.notify(); }

(am gleichen mon-Objekt) und der erste Thread (vorausgesetzt, er ist der einzige Thread, der auf dem Monitor wartet) wird aufwachen.

Sie können auch notifyAll aufrufen, wenn mehr als ein Thread auf den Monitor wartet - dies wird alle von ihnen aufwecken. Allerdings wird nur einer der Threads in der Lage sein, den Monitor zu erfassen (denken Sie daran, dass das wait in einem synchronized-Block steht) und fortfahren - die anderen werden dann blockiert, bis sie den Sperren des Monitors erwerben können.

Ein weiterer Punkt ist, dass Sie wait auf Object selbst aufrufen (d.h. Sie warten auf den Monitor eines Objekts), während Sie sleep auf Thread aufrufen.

Noch ein weiterer Punkt ist, dass Sie aus wait willkürliche Aufweckungen erhalten können (d.h. der Thread, der wartet, setzt sich aus keinem ersichtlichen Grund fort). Sie sollten immer wait verwenden, während Sie auf eine Bedingung warten, wie folgt:

synchronized {
    while (!condition) { mon.wait(); }
}

136 Stimmen

Nein, das kann es nicht. Es kann nur unterbrochen werden.

0 Stimmen

Aber Sie können einen schlafenden Thread unterbrechen. In diesem Fall ist wait() tatsächlich überflüssig und verschwendet auch CPU-Zyklen :-(

10 Stimmen

Wenn Sie unterbrechen, müssen Sie wissen, welchen Thread Sie unterbrechen möchten. Wenn Sie notify aufrufen, benötigen Sie nur ein Objekt, und es spielt keine Rolle, ob ein anderer Thread auf dieses Objekt 'wartet'. Warten/Benachrichtigen wird zur Kommunikation verwendet, während sleep zum, ähm, Schlafen verwendet wird.

361voto

Robert Munteanu Punkte 64955

Ein wesentlicher Unterschied, der noch nicht erwähnt wurde, ist, dass:

  • sleep() gibt das von ihm gehaltene Schloss am Thread nicht frei,

    synchronized(LOCK) {
        Thread.sleep(1000); // LOCK wird gehalten
    }
  • wait() gibt das von ihm gehaltene Schloss am Objekt frei.

     synchronized(LOCK) {
         LOCK.wait(); // LOCK wird nicht gehalten
     }

113 Stimmen

Das Warten gibt nur das Schloss für das Objekt frei, auf das Sie warten. Es gibt keine anderen Schlösser frei.

17 Stimmen

Sie müssen tatsächlich nicht sleep innerhalb einer Sperre aufrufen - Sperren und warten / benachrichtigen gehen Hand in Hand, aber Sperren und sleep sind nicht miteinander verbunden.

7 Stimmen

@oxbow_lakes - Ich würde sagen, dass du nicht mit Schlössern schlafen solltest, dafür gibt es nur wenige Anwendungsfälle. Wollte nur die Unterschiede hervorheben.

271voto

E-rich Punkte 8765

Ich fand diesen Beitrag hilfreich. Es erklärt den Unterschied zwischen Thread.sleep(), Thread.yield() und Object.wait() in verständlichen Worten. Um zu zitieren:

Letztendlich landet alles beim Scheduler des Betriebssystems, der Prozessen und Threads Zeitscheiben zuweist.

sleep(n) sagt „Ich bin mit meiner Zeitscheibe fertig und bitte gib mir für mindestens n Millisekunden keine neue.“ Das Betriebssystem versucht nicht einmal, den schlafenden Thread zu planen, bis die angeforderte Zeit verstrichen ist.

yield() sagt „Ich bin mit meiner Zeitscheibe fertig, habe aber noch Arbeit zu tun.“ Das Betriebssystem kann dem Thread sofort eine neue Zeitscheibe geben oder einem anderen Thread oder Prozess die CPU überlassen, die der Thread gerade aufgegeben hat.

wait() sagt „Ich bin mit meiner Zeitscheibe fertig. Gib mir keine neue Zeitscheibe, bis jemand notify() aufruft.“ Wie bei sleep() wird das Betriebssystem Ihre Aufgabe nicht planen, es sei denn, jemand ruft notify() auf (oder es treten einige andere Aufwach-Szenarien auf).

Threads verlieren auch den Rest ihrer Zeitscheibe, wenn sie blockierende E/A durchführen oder unter einigen anderen Umständen. Wenn ein Thread die gesamte Zeitscheibe durchläuft, übernimmt das Betriebssystem zwangsweise die Kontrolle, ungefähr so, als würde yield() aufgerufen, damit andere Prozesse ausgeführt werden können.

Sie benötigen yield() selten, aber wenn Sie eine rechenintensive Anwendung mit logischen Aufgabengrenzen haben, kann das Einfügen eines yield() möglicherweise die Systemreaktionsfähigkeit verbessern (auf Kosten der Zeit - Kontextwechsel, selbst nur zum Betriebssystem und zurück, sind nicht kostenlos). Messen und testen Sie gegen die Ziele, die Ihnen wichtig sind, wie immer.

0 Stimmen

Ertrag ist im Grunde plattformabhängig... javamex.com/tutorials/threads/yield.shtml

0 Stimmen

Die Erklärung von sleep(n) besagt implizit, dass der aktuell ausgeführte Thread den Monitor des Schlosses freiwillig aufgibt, was nicht wahr ist. Zitat aus Thread's javadoc: "Der Thread verliert nicht den Besitz von Monitoren".

3 Stimmen

@Jonathan es wird in der Antwort nicht erwähnt, dass Monitore eine Rolle spielen, und das liegt daran, dass sleep kein spezielles Verhalten in Bezug auf Monitore hat, als jeder andere Java-Methodenaufruf, d.h. es interagiert nicht mit ihnen oder modifiziert sie in irgendeiner Weise. Wenn du etwas über Monitore sagen würdest, solltest du angeben, dass wait zusätzlich zu den oben genannten Dingen vorübergehend das Sperren des Objekts aufheben wird, auf dem es aufgerufen wird.

73voto

estani Punkte 20703

Es gibt hier viele Antworten, aber ich konnte die erwähnte semantische Unterscheidung auf keiner finden.

Es geht nicht um den Thread selbst; beide Methoden sind erforderlich, da sie sehr unterschiedliche Anwendungsfälle unterstützen.

sleep() sendet den Thread in den Ruhezustand, wie zuvor, es speichert einfach den Kontext und stoppt die Ausführung für eine vordefinierte Zeit. Um ihn also vor Ablauf der Zeit aufzuwecken, muss man die Thread-Referenz kennen. Dies ist keine häufige Situation in einer Multi-Thread-Umgebung. Es wird hauptsächlich für die Zeit-Synchronisation (z.B. Aufwecken genau nach 3,5 Sekunden) und/oder hart kodierten Fairneß (einfach eine Weile schlafen lassen und andere Threads arbeiten lassen) verwendet.

wait() hingegen ist ein Thread (oder Nachrichten) Synchronisationsmechanismus, der es Ihnen ermöglicht, einem Thread von dem Sie keine gespeicherte Referenz haben (oder sich nicht kümmern) zu benachrichtigen. Sie können es sich wie ein Publish-Subscribe Muster vorstellen (wait == abonnieren und notify() == veröffentlichen). Im Grunde genommen senden Sie mit notify() eine Nachricht (die möglicherweise nicht einmal empfangen wird und normalerweise interessiert es Sie nicht).

Zusammenfassend verwendet man normalerweise sleep() für Zeit-Synchronisation und wait() für Multi-Thread-Synchronisation.

Sie könnten auf die gleiche Weise in dem zugrunde liegenden Betriebssystem implementiert sein oder auch nicht (da frühere Versionen von Java keine echte Multithreading-Unterstützung hatten; wahrscheinlich machen das auch einige kleine VMs nicht). Vergessen Sie nicht, dass Java auf einer VM läuft, daher wird Ihr Code je nach der VM/OS/HW, auf der er ausgeführt wird, in etwas anderes umgewandelt.

65voto

roottraveller Punkte 7134

Hier habe ich einige wichtige Unterschiede zwischen den Methoden wait() und sleep() aufgelistet.
PS: Klicken Sie auch auf die Links, um den Bibliothekscode zu sehen (interne Arbeitsweise, spielen Sie einfach ein wenig herum, um es besser zu verstehen).

wait()

  1. wait() Methode gibt den Sperrstatus frei.

  2. wait() ist die Methode der Klasse Object.

  3. wait() ist die nicht-statische Methode - public final void wait() throws InterruptedException { //...}

  4. wait() sollte durch die Methoden notify() oder notifyAll() benachrichtigt werden.

  5. wait() Methode muss in einer Schleife aufgerufen werden, um mit Fehlalarmen umzugehen.

  6. wait() Methode muss aus einem synchronisierten Kontext aufgerufen werden (d.h. synchronisierte Methode oder Block), sonst wirft es eine IllegalMonitorStateException

sleep()

  1. sleep() Methode gibt den Sperrstatus nicht frei.
  2. sleep() ist die Methode der Klasse java.lang.Thread.
  3. sleep() ist die statische Methode - public static void sleep(long millis, int nanos) throws InterruptedException { //... }
  4. nach der angegebenen Zeit ist sleep() abgeschlossen.
  5. sleep() sollte besser nicht aus einer Schleife aufgerufen werden (siehe Code unten).
  6. sleep() kann von überall aus aufgerufen werden. Es gibt keine spezifische Anforderung.

Ref: Unterschied zwischen Wait und Sleep

Codeausschnitt zum Aufrufen der wait- und sleep-Methode

synchronized(monitor){
    while(condition == true){ 
        monitor.wait()  //gibt Monitor-Sperre frei
    }

    Thread.sleep(100); //setzt aktuellen Thread auf Schlaf    
}

Thread-Übergang zu verschiedenen Thread-Zuständen

0 Stimmen

Ist es korrekt, dass ein schlafender Thread durch Aufrufe von notify() geweckt werden kann? Einige der anderen Beiträge hier scheinen anzudeuten, dass ein schlafender Thread nicht geweckt, sondern unterbrochen werden kann.

0 Stimmen

Ja, Thread.sleep() wird verwendet, um Prozessorzeit für andere Threads verfügbar zu machen. Der Schlafzeitraum kann durch Unterbrechungen (d.h. durch JVM) beendet werden. Lesen Sie dies stackoverflow.com/questions/4264355/…

0 Stimmen

Dieser Beitrag sagt auch, dass interrupt() das ist, was einen schlafenden Thread aufweckt? Ich bezog mich auf das Thread-Zustandsdiagramm, das Sie gepostet haben, in dem steht, dass notify oder notifyAll einen schlafenden (nicht wartenden) Thread wieder betriebsbereit machen. Ich möchte nur sicherstellen, dass ich das verstehe.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X