• Willkommen im Linux Club - dem deutschsprachigen Supportforum für GNU/Linux. Registriere dich kostenlos, um alle Inhalte zu sehen und Fragen zu stellen.

Java-Threads, Unterschied notify() und notifyAll()

spunti

Hacker
Hallo Kollegen,

ich hab eine Profi-Java-Frage. Die kann wahrscheinlich auch nur jemand beantworten, der sich schon mal damit beschäftigt hat.

Und zwar gibts in Java das Schlüsselwort synchronized, mit dem ich kritische Bereiche vor gleichzeitigen Zugriff durch mehrere Threads schützen kann. Also z.B. damit nicht einer gleichzeitig in eine Variable was reinschreibt, während der andere die gerade ausliest.

So, dann gibts die Methode wait(), damit kann der Thread, der gerade in einem synchronized-Bereich ist, sich schlafenlegen und die Sperre kurzzeitig freigeben.
Andere Threads dürfen also in den synchronisierten Bereich eintreten. (Oder in einen anderen synchronisierten Bereich, der am selben Objekt synchronisiert wird.)

Der neue Thread kann jetzt notify() oder notifyAll() aufrufen, wenn er mit seiner Arbeit fertig ist und dann kann ein eventuell durch wait() wartender Thread weiterarbeiten.

Mein Problem ist jetzt, was genau ist der Unterschied zwischen notify() und notifyAll()?

notify() weckt zufällig genau einen wartenden Thread wieder auf.
notifyAll() weckt alle wartenden Threads auf, aber wie bei notify kann auch nur einer weiterarbeiten und die anderen werden durch die Sperre ausgesperrt und schlafen weiter.

Also genau dasselbe. Man kann nicht genau sagen, welcher von den Thread weiterarbeitet und es ist auch immer nur einer!

Jetzt steht im Buch "Java Threads" von Oaks/Wong, daß wenn mehrere Threads aufgeweckt werden, beispielsweise nur einer effektiv weiterarbeiten kann, weil die anderen etwa noch auf eine weitere Bedingung warten.
Eine deutsche Übersetzung/Zusammenfassung von dem Abschnitt gibt es z.B. unter:
http://www.informatik.fh-muenchen.de/~schieder/concurrent-java-ss99/03-schalk-wait-notify/main.htm
Und das Codebeispiel dazu unter:
http://www.informatik.fh-muenchen.de/~schieder/concurrent-java-ss99/03-schalk-wait-notify/ResourceThrottle.java

Leider geht das exakt an meiner Frage vorbei und die klären gar nicht, was nun der Unterschied ist oder ich hab einen Denkfehler!

Ich frag mich nämlich, wie Java das rauskriegen will, wer effektiv weiterarbeiten kann. Funktioniert das von alleine wie durch Zauberhand? Denn in den Threads selber werde ich ja sowas nicht einbauen können, da nur einer ausgeführt wird wegen der Sperre.

In einem anderen Buch (glaube in der Javainsel) hab ich noch einen anderen Denkansatz gefunden, der uns da vielleicht auch weiterhelfen kann. Und zwar gibt es für wait() folgendes Codemuster:

while (!condition)
try { wait(); } catch (InterruptedException e) {}

Wenn jetzt wait() aufgerufen wurde und später notify() oder notifyAll(), dann setzt der Thread nicht genau nach wait fort, sondern überprüft erst die Bedingung in der while-Schleife. Würde wait() innerhalb eines if-Blocks stehen, würde die Bedingung nicht erneut geprüft!

Ist das vielleicht schon die Lösung des Problems? Daß mehrere Threads bei notifyAll() aufwachen und die doch alle gleichzeitig von allein prüfen, ob die andere Bedingung (also !condition) noch erfüllt ist und dann einer von den Threds weiterarbeitet und die anderen aussperrt, für den das gilt?

Ist wie gesagt wohl ein Profi-Problem, aber vielleicht hat ja einer dazu eine Meinung oder dazu was in einer Vorlesung gehört?

danke
spunti
 

Yogi_B

Member
So aus dem Stehgreif gebe ich dir jetzt mal recht :wink:

JAVA entscheidet selber wann und welcher Thread laufen darf.
Black-Magic like Garbage-Collector :roll:

Es kann sein, dass die VM für deine Condition eine Semaphore o.ä. baut. Aber wer weiss das bei JAVA schon.
Jedenfalls wenn verschiedene Thread auf ein uns das selbe "Ding" warten kannste Du nie sicher sein welcher zu erst weiter läuft.
 
OP
S

spunti

Hacker
Ich hab jetzt doch noch die Antwort schwarz auf weiß gefunden. In "Effektiv Java programmieren" von Bloch steht auf Seite 203, daß alle Threads aufwachen und dann wirklich alle (ich nehmen stark an, nacheinander) die Bedingung in der while-Schleife testen. Wenn die Bedingung der Schleife nicht erfüllt ist, legen sie sich wieder schalfen. Somit ist gesichert, daß - wenn ein Thread existiert, der wirklich wieterarbeiten kann dieser auch wach bleibt.

Das klärt erst mal meine Grundsatzfrage. Offen bleibt, was passiert, wenn für mehrere Threads die Bedingung erfüllt ist. Das Codebeispiel von Oaks/Wong (sieht link im Posting oben) suggeriert, daß dann mehrere Threads weiterlaufen. In "effektiv Java programieren" ist der Punkt auch nicht ganz klar. Sieht aber auch so aus, als wenn dann mehrere Threads gleichzeitig weiterarbeiten dürfen.

Damit ist aber die Sperre von synchronized ausgehebelt und mehrere Threads können gleichzeitig auf kritische Bereiche zugreifen, was Fehler hervorrufen sollte. Komisch, komisch...

spunti
 

Yogi_B

Member
So ungefähr hätte ich es mir auch gedacht, nur auf einem System ohne smp läuft ja immer nur ein Thread. Da weisste nie wer als nächster dran kommt.
 
OP
S

spunti

Hacker
Ich weiß nicht genau, was "smp" heißen soll, aber Threads arbeiten auf Ein-Prozessor-Maschinen wirklich nicht parallel, wenn du das meinst. Trotzdem gibts sogar hier Vorteile: Wenn ein Thread auf einen I/O-Stream warten muß kann der andere z.B. schon weiterarbeiten/rechnen.
Bei GUI-Anwendungen also durchaus sinnvoll. Ein weiterer Vorteil soll der sein, daß man gezwungen ist, genaueren Code zu schreiben. Aber davon halte ich nichts. Es ist äußerst kompliziert und man kann Fehler einbauen, die man nur manchmal, nur zur Laufzeit und nur Maschinenabhängig auftreten.

Zu meinem neuen Problem, ob wirklich mehrere Threads parallel weiterarbeiten dürfen, wenn sie geweckt sind und die Bedingung gilt, hat ein Kollege geschrieben:
Es könnte sein, daß genau 1 Thread weiterarbeit, aber die anderen Threads, für die die Bedingung der while-Schleife gültig ist, trotzdem wach sind. Die würden dann quasi weiterarbeiten, sobald der aktive Thread den geschützten synchronized-Bereich verlassen hat - also ohne weiteres notify!
Aber diese These halte ich für sehr gewagt. Dafür finde ich in der Literatur keine Hinweise, aber auch (leider) nichts, was dem widerspräche.
Mal sehen, vielleicht kann ich durch Tests da noch was ausschließen.

spunti
 

Yogi_B

Member
symetic multi processor (Mehr als eine CPU)

Bei GUI-Anwendungen ist mehr als ein Thread eh immer kritisch. SWING ist ein Thread, Dein Programm auch noch...

Aber dieses Problem haste nicht nur unter JAVA, sowas kenne ich noch sehr gut aus C++ Zeiten.
Da ne Reihenfolge reinzubekommen, soviele Mutexe kannste garnicht verbasteln :wink:
 
Oben