# Unterschied zwischen notify() und notifyAll()



## spunti (23. Mai 2004)

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.d...9/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


----------



## Beni (23. Mai 2004)

Nimm jetzt nichts für bare Münze:

Bei "notify" startet genau ein Thread.
Bei "notifyAll" starten alle Threads, auch wenn einige sofort wieder warten müssen.

Die Threads die nach "notify" noch warten, benötigen weitere Aufrufe von "notify" oder "notifyAll".
Die Threads die nach "notifyAll" noch warten, starten sobald sie die Gelegenheit dazu haben. _Der Programmiere muss sie nicht mehr aufwecken, das geschieht automatisch._

Hm, hilft das? (stimmt das?)


----------



## spunti (24. Mai 2004)

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

PS:
Deine Theorie, daß nur 1 Thread weitermacht und die anderen, die aufgrund ihrer Bedingung auch weiterarbeiten könnten nicht mehr extra geweckt werden müssen, klingt nicht dumm.
Die würden dann warten bis der eine aktive Thread die Sperre freigibt und hätten dann eine Art Vorrecht auf das Weiterarbeiten - sogar ohne weiteres notify.
Dann würden nicht mehrere Threads gleichzeitig auf eine gesperrte Methode zugreifen und trotzdem wären sie in etwa wach. Aber dafür hab ich bis jetzt noch keinen Hinweis in der Literatur gefunden - aber auch (leider) nichts, was dem widerspräche.
Mal sehen, vielleicht kann ich da was austesten und so etwas ausschließen, falls nieman dazu was weiß....


----------

