Dies ist eine alte Version des Dokuments!
Inhaltsverzeichnis
Erzeuger-Verbraucher-Probleme
Bob und Lisa betreiben zusammen eine Pizzaria. Während Bob in der Küche die Pizzen bäckt, bedient Lisa die Kunden im Restaurantbereich. Zwischen den Bereichen befindet sich in der Wand eine Öffnung mit einem kleinen Tresen. Immer wenn Bob eine Pizza fertiggebacken hat, legt er sie auf den Tresen. Lisa schaut immer wieder beim Tresen vorbei und sieht nach, ob Pizzen draufliegen, die sie abholen und an die Tische bringen kann.
- Lisa findet es anstrengend, immer wieder beim Tresen vorbeizuschauen um nachzusehen, ob neue Pizzen fertig sind.
- Oft ist der Tresen aber auch voll und Bob muss warten, bis er neue Pizzen drauflegen kann.
Lisa schlägt vor, eine Tischglocke auf den Tresen zu stellen. Erklären Sie ihre Idee.
Das Erzeuger-Verbraucher-Problem tritt in der Informatik immer dann auf, wenn es Threads gibt, die Ressourcen erzeugen und in einem Ablagebereich mit beschränkter Kapazität ablegen während andere Threads, die Ressourcen aus dem Bereich entnehmen und verbrauchen.
- Ein ungünstiger Lösungsansatz besteht im aktiven Warten, d.h. Erzeuger sehen immer wieder nach, ob der Ablagebereich wieder Platz hat um Ressourcen abzulegen und Verbraucher sehen immer wieder nach, ob im Ablagebereich schon wieder Ressourcen da sind um abgeholt zu werden.
- Besser ist passives Warten:
- Der Erzeuger sieht nach, ob Platz im Ablagebereich ist.
- Falls "ja", legt er Ressourcen ab und benachrichtigt den Verbraucher. Falls dieser im Wartezustand ist, "wacht er auf".
- Falls "nein", geht er in einen Wartezustand, der keine Systemressourcen verbraucht.
- Der Verbraucher seht nach, ob Ressourcen im Ablagebereich sind.
- Falls "ja", nimmt er welche heraus und benachrichtigt den Erzeuger. Falls dieser im Wartezustand ist, "wacht er auf".
- Falls "nein", geht er in einen Wartezustand, der keine Systemressourcen verbraucht.
Um passives Warten zu ermöglichen besitzt der Monitor die Methoden wait()
(versetzt den aktuellen Thread in den Wartezustand) und notify()
(holt einen der Wartenden Threads aus dem Wartezustand).
Aktives Warten
Passives Warten
Das zentrale Element des nachfolgenden Programms sind die Methoden legPizzaDrauf
und holPizzaAb
:
class Tresen { int anzahlPizzen = 0; synchronized void legPizzaDrauf() { while (anzahlPizzen == 1) { wait(); // aktueller Thread geht in den Wartezustand und blockiert } anzahlPizzen = 1; notify(); // beliebigen Thread aus dem Wartezustand "aufwecken" } synchronized void holPizzaAb() { while(anzahlPizzen == 0) { wait(); // aktueller Thread geht in den Wartezustand und blockiert } anzahlPizzen = 0; notify(); // beliebigen Thread aus dem Wartezustand "aufwecken" } }
In der folgenden Darstellung ist Bobs Thread blau gekennzeichnet, Lisas Thread grün. Die Stelle, an der sich der Thread jeweils befindet, ist mit einem Punkt gekennzeichnet. Der hellrot hinterlegte Bereich kennzeichnet das Tresen-Objekt mit seinen synchronized
-Methoden und seinem Zustand (anzahlPizzen
).
Stellen Sie sich mit Hilfe der Darstellung Bob und Alice vor, wie
- sie sich unterschiedlich schnell im Kreis bewegen,
- warten (
wait()
), - einander mit der Glocke bescheidgeben (
notify()
) - und wie sich dabei jeweils der Zustand des Tresen-Objekts (d.h.
anzahlPizzen
) verändert.