Vor dem Zusammenbau eines Autos muss der Lagerverwalter zuerst prüfen, ob genügend Einzelteile eingelagert sind, bevor der Hersteller sie entnehmen kann. Die Lieferanten und Hersteller greifen irgendwann auf das Lager zu, eventuell auch gleichzeitig. In einer solchen Situation muss der Lagerverwalter aufpassen: die verschiedenen Lieferanten können gleichzeitig ihre Waren abladen. Bei der Ausstellung der Empfangsbestätigungen muss der Lagerverwalter sequentiell vorgehen; er kann nur einen Lieferanten nach dem anderen bedienen und jedes mal gleich den Lagerbestand in seiner Buchführung aktualisieren. Will der Hersteller Teile entnehmen, muss er eventuell warten, bis der Lagerbestand die Eingänge verbucht hat, bevor er seinen Lieferschein und die Waren bekomm. Der Zugriff auf den Lagerbestand ist also kritisch.
Das Lager hat für jedes Produkt eine bestimmte Lagerkapazität. Liefern die Lieferanten zu schnell oder entnimmt der Herstelle die Teile zu langsam, ist die Lagerkapazität erschöpft; der Lieferant kann seine Ware nicht abladen und muss vor dem Lager warten, bis der Hersteller die Waren entnommen hat.
Java verfügt zur Programmierung dieses Szenarios über Sprachmittel zur Synchronisierung der Zugriffe auf kritische Daten. Im Beispiel sind Bestand und Lagerkapazität die kritischen Daten.
Zuerst müssen die kritischen Methoden der Klasse Lager synchronisiert werden. Hierzu versehen wir die beiden Methoden liefern und entnehmen mit dem Schlüsselwort synchronized. Dies bedeutet, dass zu einem bestimmten Zeitpunkt immer nur ein Lieferant oder der Hersteller Waren aus dem Lager entnehmen kann.
Wenn der Lieferant liefern will, ruft er die synchronisierte Methode "liefern" auf und blockiert damit das Lager. Ist im Lager noch Lagerkapazität frei, liefert er einfach aus und gibt das Lager wieder frei. Wenn die Kapazität aber erschöpft ist, muss er das Lager freiwillig freigeben, damit der Hersteller Waren entnehmen und dadurch freien Lagerplatz schaffen kann. Der Lieferant gibt dann durch den Aufruf der Methode wait() das Lager frei.
In diesem Fall reiht sich dieser Thread in eine Warteschlange ein und wartet, bis er seine Ware liefern kann. Der Hersteller müsste nach der Entnahme von Waren von sich aus den oder die wartenden Lieferanten informieren, wenn es wieder freie Lagerkapazität gibt. Dies macht er, indem er nach der Entnahme der Ware die Methode notify() aufruft. Jetzt konkurrieren alle wartenden Lieferanten darum, ihre Ware auszuliefern. Das Java-Laufzeitsystem wählt einen Lieferanten aus der Warteschlange, der dann eventuell ausliefern kann und danach das Lager endgültig frei gibt.
public synchronized void liefern(int produkt) { while(bestand[produkt]>kapazitaeten[produkt]) { try { wait(); } catch (InterruptedException e) { } } ... notify(); }
© Ralph-Erich Hildebrandt, 27. September 2004