2008-10-22 9 views
33

Jemand bei der Arbeit fragte nur nach dem Grund hinter der Notwendigkeit, eine Wartezeit in eine synchronisierte zu wickeln.Kann jemand Thread-Monitore erklären und warten?

Ehrlich gesagt kann ich die Argumentation nicht sehen. Ich verstehe, was die Javadocs sagen - dass der Thread der Besitzer des Monitors des Objekts sein muss, aber warum? Welche Probleme verhindert es? (Und wenn es tatsächlich notwendig ist, warum kann nicht das Warten Methode bekommen Sie den Monitor selbst?)

ich für eine ziemlich im Detail, warum oder vielleicht einen Verweis auf einen Artikel suchen. Ich konnte keinen in einem schnellen Google finden.

Oh, auch, wie vergleicht thread.sleep?

bearbeiten: Große Reihe von Antworten - Ich wünschte wirklich, ich könnte mehr als eine auswählen, weil sie mir geholfen haben zu verstehen, was los war.

Antwort

3

Wenn das Objekt den Objektmonitor beim Aufrufen von Object.wait() nicht besitzt, kann es nicht auf das Objekt zugreifen, um einen Benachrichtigungslistener einzurichten, bis der Monitor freigegeben wird. Stattdessen wird es als Thread behandelt, der versucht, auf eine Methode auf einem synchronisierten Objekt zuzugreifen.

Oder um es anders auszudrücken, gibt es keinen Unterschied zwischen:

public void doStuffOnThisObject() 

und das folgende Verfahren:

public void wait() 

Beide Methoden werden blockiert, bis das Objekt Monitor freigegeben wird. Dies ist eine Funktion in Java, die verhindert, dass der Status eines Objekts von mehr als einem Thread aktualisiert wird. Es hat einfach unbeabsichtigte Auswirkungen auf die Methode wait().

Vermutlich wird die Methode wait() nicht synchronisiert, da dies Situationen verursachen kann, in denen der Thread mehrere Sperren für das Objekt hat. (Weitere Informationen hierzu finden Sie unter Java Language Specifications/Locking.) Mehrere Sperren sind ein Problem, da die Methode wait() nur eine Sperre rückgängig macht. Wenn die Methode synchronisiert würde, würde dies garantieren, dass nur die Sperre der Methode rückgängig gemacht würde, während immer noch eine mögliche äußere Sperre rückgängig gemacht würde. Dies würde eine Deadlock-Bedingung im Code verursachen.

Um Ihre Frage zu beantworten Thread.sleep(), Thread.sleep() garantiert nicht, dass das, was Bedingung Sie warten erfüllt ist. Mit Object.wait() und Object.notify() kann ein Programmierer die Blockierung manuell implementieren. Die Threads entsperren, sobald eine Benachrichtigung gesendet wird, dass eine Bedingung erfüllt wurde. z.B. Ein Lesevorgang von der Festplatte ist beendet und Daten können vom Thread verarbeitet werden. Thread.sleep() würde erfordern, dass der Programmierer abfragt, ob die Bedingung erfüllt wurde, und dann in den Ruhezustand zurückfallen, wenn dies nicht der Fall ist.

+0

Ich verstehe synchronisiert. Die Frage war, warum muss object.wait() den Monitor besitzen, oder warum kann die Erfassung dieses Monitors nicht innerhalb des Objekts eingekapselt werden.wait() Methode (oder ist das was Thread.sleep() tut? –

+0

Sorry, ich missverstanden. Antwort wurde aktualisiert. Beantwortet das Ihre Frage besser? – 64BitBob

+1

Ja, das macht viel Sinn, obwohl die offene Frage ist immer noch "Warum kann die Wartemethode nicht einfach selbst synchronisiert werden?" –

4

Es braucht den Monitor zu besitzen, da der Zweck der wait(), um den Monitor zu lösen ist und lassen Sie andere Threads den Monitor zu tun Verarbeitung ihrer eigenen erhalten. Der Zweck dieser Methoden (wait/notify) besteht darin, den Zugriff auf synchronisierte Codebausteine ​​zwischen zwei Threads zu koordinieren, die einander zur Ausführung bestimmter Funktionen benötigen. Es geht nicht nur darum sicherzustellen, dass der Zugriff auf eine Datenstruktur Thread-sicher ist, sondern um Ereignisse zwischen mehreren Threads zu koordinieren.

Ein klassisches Beispiel wäre ein Erzeuger/Verbraucher Fall sein, wenn ein Thread Daten in eine Warteschlange schiebt, und ein anderer Thread verbraucht die Daten. Der konsumierende Thread würde immer den Zugriff des Monitors auf die Warteschlange erfordern, würde jedoch den Monitor freigeben, sobald die Warteschlange leer ist. Der Producer-Thread würde dann nur Zugriff erhalten, um in den Thread zu schreiben, wenn der Konsument nicht mehr weiterarbeitet. Es würde den Konsumenten-Thread benachrichtigen, sobald es mehr Daten in die Warteschlange geschoben hat, so dass es den Monitor wiedergewinnen und erneut auf die Warteschlange zugreifen kann.

+0

Guter Punkt, aber was ist mit dem Fall, wo Sie einfach auf eine Benachrichtigung von einem anderen Thread warten wollen, nicht einen Monitor freigeben, damit ein anderer Thread es haben kann du sagst "Threa d.sleep "ist für diese Verwendung besser geeignet? –

+0

In diesem Fall sollten Sie wahrscheinlich einen anderen Monitor erstellen, um zwischen diesen beiden Threads zu synchronisieren. –

+0

Wenn keine gemeinsame Nutzung von Datenstrukturen erforderlich ist, Sie aber lediglich auf ein Ereignis warten, reicht möglicherweise ein Ruhezustand aus, aber der Ereignisthread muss einen Interrupt auslösen, um den schlafenden Thread aufzuwecken (sofern nicht zeitgesteuert). Das bedeutet, dass es Zugriff auf das Thread-Objekt benötigen würde. – Robin

5

Warten gibt den Monitor auf, Sie müssen ihn also aufgeben. Notify muss auch den Monitor haben.

Der Hauptgrund, warum Sie dies tun möchten, ist sicherzustellen, dass Sie den Monitor haben, wenn Sie von wait() zurückkommen - normalerweise verwenden Sie das wait/notify-Protokoll, um einige gemeinsam genutzte Ressourcen zu schützen um sicher zu sein, es zu berühren, wenn die Wartezeit zurückkehrt. Das selbe mit notify - normalerweise ändern Sie etwas und rufen dann notify() auf - Sie möchten den Monitor haben, Änderungen vornehmen und notify() aufrufen.

Wenn Sie eine Funktion wie folgt aus:

public void synchWait() { 
    syncronized { wait(); } 
} 

Sie würden nicht den Monitor, wenn Wartezurück - Sie werden es bekommen konnte, aber man kann es nicht weiter erhalten.

2

Hier ist mein Verständnis, warum die Einschränkung tatsächlich eine Anforderung ist. Ich basiere dies auf einer C++ - Monitor-Implementierung, die ich vor einiger Zeit gemacht habe, indem ich einen Mutex und eine Zustandsvariable kombiniert habe.

In einem Mutex + condition_variable = Monitor System setzt der Aufruf wait die Zustandsvariable in einen Wartezustand und gibt den Mutex frei. Die Bedingungsvariable ist ein gemeinsamer Status und muss daher gesperrt werden, um Race-Bedingungen zwischen Threads, die warten möchten, und Threads, die benachrichtigt werden möchten, zu vermeiden. Anstatt einen weiteren Mutex einzuführen, um seinen Zustand zu sperren, wird der existierende Mutex verwendet. In Java ist der Mutex korrekt gesperrt, wenn der Thread, der den Thread wartet, den Monitor besitzt.

13

Viele gute Antworten hier schon. Aber ich möchte hier nur erwähnen, dass das andere MUSS bei der Verwendung von wait() tun muss, es in einer Schleife auszuführen, abhängig von der Bedingung, auf die Sie warten, falls Sie weckende Wakeups sehen, die meiner Erfahrung nach passieren.

Um aus einem anderen Thread zu warten, um eine Bedingung true zu ändern und mitteilen:

synchronized(o) { 
    while(! checkCondition()) { 
    o.wait(); 
    } 
} 

Natürlich, in diesen Tagen, würde ich empfehlen, nur das Objekt neu Bedingung verwendet, wie es klarer und verfügt über mehr Features (wie erlauben mehrere Bedingungen pro Sperre, in der Lage, Warteschlange Länge, flexibler Zeitplan/Interrupt, etc. zu überprüfen).

Lock lock = new ReentrantLock(); 
Condition condition = lock.newCondition(); 
lock.lock(); 
try { 
    while (! checkCondition()) { 
    condition.await(); 
    } 
} finally { 
    lock.unlock(); 
} 

}

2

Meist getan warten wird, wenn es eine Bedingung ist, sagen eine Warteschlange leer ist.

If(queue is empty) 
    queue.wait(); 

Nehmen wir an, die Warteschlange ist leer. Wenn der aktuelle Thread nach dem Prüfen der Warteschlange vorgeht, wenn ein anderer Thread der Warteschlange einige Elemente hinzufügt, wird der aktuelle Thread dies nicht wissen und wird auf den Zustand Warten warten. Das ist falsch. Also sollten wir so etwas wie

Synchornized(queue) 
{ 
    if(queue is empty) 
      queue.wait(); 
} 

Jetzt haben wir uns überlegen, was, wenn sie sich als synchronisiert warten lassen. Wie bereits in einem der Kommentare erwähnt, gibt es nur eine Sperre frei. Das heißt, wenn wait() im obigen Code synchronisiert wurde, wäre nur eine Sperre freigegeben worden. Impliziert, dass der aktuelle Thread mit der Sperre für die Warteschlange warten wird.