Warum verfügen alle Java-Objekte über wait() und notify() und führt dies zu Leistungseinbußen?

StackOverflow https://stackoverflow.com/questions/1648551

  •  22-07-2019
  •  | 
  •  

Frage

Jedes Java Object hat die Methoden wait() Und notify() (und weitere Varianten).Ich habe diese noch nie verwendet und ich vermute, dass viele andere dies auch nicht getan haben.Warum sind diese so grundlegend, dass jedes Objekt sie haben muss, und gibt es Leistungseinbußen, wenn sie vorhanden sind (vermutlich wird ein gewisser Zustand in ihnen gespeichert)?

BEARBEITEN um die Frage zu betonen.Wenn ich eine habe List<Double> mit 100.000 Elementen dann alle Double verfügt über diese Methoden, da es von erweitert wird Object.Aber es scheint unwahrscheinlich, dass alle diese über die Threads Bescheid wissen müssen, die das verwalten List.

BEARBEITEN ausgezeichnete und nützliche Antworten.@Jon hat einen sehr guten Blogbeitrag, der mein Bauchgefühl zum Ausdruck bringt.Ich stimme @Bob_Cross auch voll und ganz zu, dass Sie ein Leistungsproblem anzeigen sollten, bevor Sie sich darüber Gedanken machen.(Auch als das n-te Gesetz erfolgreicher Sprachen: Wenn es ein Leistungseinbruch gewesen wäre, hätte Sun oder jemand es behoben.)

War es hilfreich?

Lösung

Nun, es bedeutet, dass jedes Objekt hat möglicherweise hat einen Monitor mit ihm verbunden ist. Der gleiche Monitor ist für synchronized verwendet. Wenn Sie mit der Entscheidung einverstanden zu jedem Objekt synchronisieren zu können, dann wait() und notify() fügen Sie nicht mehr pro-Objekt-Zustand. Die JVM kann die tatsächliche Monitor zuweisen lazily (ich weiß, .NET tut), aber es hat einige Speicherplatz zur Verfügung zu sagen sein, welcher Monitor mit dem Objekt verbunden ist. Zugegeben möglich ist es, dass dies eine sehr kleine Menge (zB 3 Byte), die jeden Speicher ohnehin nicht wirklich wegen Polsterung des Restes des Objekts Kopfes retten würde - würden Sie an, wie jeder einzelner JVM behandeln Speicher aussehen müssen sagen sicher.

Beachten Sie, dass nur zusätzliche mit Methoden hat keinen Einfluss auf die Leistung (außer sehr etwas wegen der Code offensichtlich vorhanden ist irgendwo ). Es ist nicht wie jedes Objekt oder sogar jede Art seine eigene Kopie des Codes für wait() und notify() hat. Je nachdem, wie die vtables arbeiteten, jeder Typen kann am Ende für jede geerbte Methode mit einem zusätzlichen V-Tabelle Eintrag nach oben - aber das ist nach wie vor nur auf einer Pro-Typ-Basis, keine Objektebene. Das ist im Grunde in dem Lärm im Vergleich mit dem Volumen des Speichers verloren gehen zu lassen, die für die eigentlichen Objekte selbst ist.

Ich persönlich glaube, dass beide .NET und Java einen Fehler gemacht, indem Sie einen Monitor mit jedem Objekt verknüpfen - Ich würde eher explizite Synchronisation Objekte stattdessen haben. Ich schrieb ein bisschen mehr dazu in einer Blog-Post über Redesign java.lang.Object / System.Object .

Andere Tipps

Warum sind diese so grundlegend, dass jedes Objekt sie haben muss und gibt es eine Leistung, die sie hat (vermutlich wird ein Staat in ihnen gespeichert)?

tl;dr:Es handelt sich um Thread-Sicherheitsmethoden, deren Kosten im Verhältnis zu ihrem Wert gering sind.

Die grundlegenden Realitäten, die diese Methoden Unterstützung sind:

  1. Java ist immer multithreaded.Beispiel:Sehen Sie sich die Liste der Threads an, die von einem Prozess mit jconsole oder jvisualvm verwendet werden.
  2. Korrektheit ist wichtiger als "Leistung". Als ich (vor vielen Jahren) Projekte bewertete wirklich schnell ist immer noch falsch.“

Grundsätzlich stellen diese Methoden einige der Hooks zum Verwalten der bei der Synchronisierung verwendeten objektbezogenen Monitore bereit.Insbesondere, wenn ja synchronized(objectWithMonitor) in einer bestimmten Methode kann ich verwenden objectWithMonitor.wait() um diesen Monitor bereitzustellen (z. B. wenn ich eine andere Methode benötige, um eine Berechnung abzuschließen, bevor ich fortfahren kann).In diesem Fall kann eine andere Methode, die blockiert wurde und auf diesen Monitor wartet, fortfahren.

Andererseits kann ich gebrauchen objectWithMonitor.notifyAll() um Threads, die auf den Monitor warten, mitzuteilen, dass ich den Monitor bald abgeben werde.Sie können jedoch erst fortfahren, wenn ich den synchronisierten Block verlasse.

Im Hinblick auf bestimmte Beispiele (z. B. lange Doppellisten), bei denen Sie befürchten könnten, dass es zu Leistungs- oder Speichereinbußen beim Überwachungsmechanismus kommt, sind hier einige Punkte, die Sie wahrscheinlich berücksichtigen sollten:

  1. Beweisen Sie es zunächst.Wenn Sie glauben, dass ein zentraler Java-Mechanismus wie die Multithread-Korrektheit große Auswirkungen hat, ist die Wahrscheinlichkeit groß, dass Ihre Intuition falsch ist.Messen Sie zunächst die Wirkung.Wenn es ernst ist und Sie wissen Damit Sie nie eine Synchronisierung auf ein einzelnes Double durchführen müssen, sollten Sie stattdessen die Verwendung von Doubles in Betracht ziehen.
  2. Wenn Sie nicht sicher sind, ob Sie, Ihr Kollege, ein zukünftiger Wartungsprogrammierer (der vielleicht ein Jahr später Sie selbst sein könnte) usw., dies niemals tun werden immer Wenn Sie eine feine Granularität des detaillierten Zugriffs auf Ihre Daten benötigen, ist die Wahrscheinlichkeit groß, dass der Wegfall dieser Monitore Ihren Code nur weniger flexibel und wartbar machen würde.

Follow-up als Antwort auf die Frage zu Pro-Objekt vs.explizite Monitorobjekte:

Kurze Antwort: @JonSkeet:Ja, das Entfernen der Monitore würde zu Problemen führen:es würde Reibung erzeugen.Behalte die Monitore drin Object erinnert uns daran, dass dies so ist stets ein Multithread-System.

Die integrierten Objektmonitore sind nicht anspruchsvoll, aber sie sind:leicht zu erklären;auf vorhersehbare Weise arbeiten;und sind in ihrem Zweck klar. synchronized(this) ist eine klare Absichtserklärung.Wenn wir unerfahrene Programmierer dazu zwingen, ausschließlich das Parallelitätspaket zu verwenden, führen wir zu Reibungen.Was ist in diesem Paket?Was ist ein Semaphor?Fork-Join?

Ein unerfahrener Programmierer kann die Objektmonitore verwenden, um anständigen Model-View-Controller-Code zu schreiben. synchronized, wait Und notifyAll kann verwendet werden, um naive Thread-Sicherheit (im Sinne einer einfachen, zugänglichen, aber möglicherweise nicht auf dem neuesten Stand befindlichen Leistung) zu implementieren.Das kanonische Beispiel wäre eines dieser Doubles (vom OP postuliert), bei dem ein Thread einen Wert festlegen kann, während der AWT-Thread den Wert erhält, um ihn auf ein JLabel zu setzen.In diesem Fall gibt es keinen guten Grund, ein explizites zusätzliches Objekt zu erstellen, nur um einen externen Monitor zu haben.

Auf einem etwas höheren Komplexitätsniveau sind dieselben Methoden als externe Überwachungsmethode nützlich.Im obigen Beispiel habe ich das explizit getan (siehe objectWithMonitor-Fragmente oben).Auch diese Methoden sind sehr praktisch, um eine relativ einfache Thread-Sicherheit zusammenzustellen.

Wenn Sie noch anspruchsvoller sein möchten, sollten Sie meiner Meinung nach ernsthaft über das Lesen nachdenken Java-Parallelität in der Praxis (falls Sie es noch nicht getan haben).Lese- und Schreibsperren sind sehr leistungsfähig, ohne zu viel zusätzliche Komplexität hinzuzufügen.

Pointe: Mit einfachen Synchronisierungsmethoden können Sie einen großen Teil der Leistung moderner Multicore-Prozessoren mit Thread-Sicherheit und ohne großen Overhead nutzen.

Alle Objekte in Java haben Monitore mit ihnen verbunden sind. Synchronisierungsgrund ist nützlich in so ziemlich alle Multi-Threaded-Code und sein semantisch sehr schön auf dem Objekt zu synchronisieren (s) Sie zugreifen, anstatt auf separate „Monitor“ Objekte.

Java können die Monitore verteilen mit den Objekten zugeordnet sind, wie benötigt - wie .NET tut - und in jedem Fall die tatsächliche Aufwand für einfach Zuteilung (wobei jedoch nicht) die Sperre wäre ziemlich klein

.

Kurz gesagt:. Es ist wirklich bequem zu speichern Objekte mit ihren Thread-Sicherheit Unterstützung Bits, und es gibt sehr wenig Auswirkungen auf die Leistung

Diese Methoden sind Umgebung Inter-Thread-Kommunikation zu implementieren.

Überprüfen Sie dieser Artikel über das Thema .

Die Regeln für dieses Verfahren aus diesem Artikel entnommen:

  • wait () teilt dem aufrufenden Thread den Monitor zu verzichten und gehen, bis eine andere schlafen   Gewinde tritt in den gleichen Monitor und Anrufe notify ().
  • notify () weckt den ersten Faden wieder auf, die wait () auf demselben Objekt aufgerufen.
  • notifyAll () aufwacht alle Fäden, die wait () auf demselben Objekt aufgerufen. Das   höchste Priorität Thread läuft zuerst.

Hope, das hilft ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top