/*************************************************************/ /* Prof. Dr. Carsten Vogt */ /* FH Koeln, Fak. 07 / Nachrichtentechnik */ /* http://www.nt.fh-koeln.de/vogt */ /* */ /* Lösung des Erzeuger-Verbraucher-Problems */ /* mit synchronized, wait() und notify() */ /*************************************************************/ // grundlegende Werte für die Simulation class Basiswerte { static int gesamtdauer = 20000; // Gesamtlaufzeit des Programms (in ms) static int erzeugungsdauer = 1000; // Zeitdauer zum Erzeugen eines Werts (außerhalb des kritischen Abschnitts) static int verbrauchsdauer = 5000; // Zeitdauer zum Verbrauchen eines Werts (außerhalb des kritischen Abschnitts) static int schreibdauer = 1000; // Zeitdauer zum Schreiben eines Werts in den Puffer (im kritischen Abschnitt) static int lesedauer = 1000; // Zeitdauer zum Lesen eines Werts aus dem Puffer (im kritischen Abschnitt) static int pufferkapazitaet = 3; // Kapazität des Puffers } // Pufferspeicher class Puffer { // Attribute private int inhalt[]; // Werte, die im Puffer gespeichert sind (Array wird als Ringpuffer benutzt) private int kap; // Kapazität = Anzahl der Werte, die der Puffer maximal aufnehmen kann private int leseindex, schreibindex; // Index bzgl. 'inhalt[]', mit dem die nächste Lese- bzw. Schreiboperation stattfindet // Konstruktor Puffer() { kap = Basiswerte.pufferkapazitaet; inhalt = new int[kap+1]; // Array hat einen Platz mehr als die Kapazität, um die Fälle "Puffer ist leer" ('leseindex'=='schreibindex') // und "Puffer ist voll" ('schreibindex' steht eine Position hinter 'leseindex') unterscheiden zu können leseindex = schreibindex = 0; } // 'schreibe()' schreibt den Wert 'wert' in den Puffer (wechselseitig ausgeschlossen zu 'lies()') synchronized void schreibe(int wert) { // blockiere durch 'wait()', wenn der Puffer voll ist if (voll()) try { System.out.println("Puffer voll => Erzeuger blockiert"); wait(); } catch (Exception e) { } System.out.println("Schreiben beginnt"); // schreibe Wert in den Puffer und setze 'schreibindex' zyklisch um 1 weiter try { Thread.sleep(Basiswerte.schreibdauer); } catch (Exception e) { } inhalt[schreibindex] = wert; schreibindex = (schreibindex+1)%(kap+1); System.out.println(" "+wert+" geschrieben"); ausgabe(); System.out.println("Schreiben endet"); // benachrichtige wartenden Thread (konkret: Verbraucher-Thread, der möglicherweise in 'lies()' wartet) notify(); } // Ende 'schreibe()' // 'lies()' liest einen Wert aus dem Puffer und liefert ihn zurück (wechselseitig ausgeschlossen zu 'schreibe()') synchronized int lies() { // blockiere durch 'wait()', wenn der Puffer leer ist if (leer()) try { System.out.println("Puffer leer => Verbraucher blockiert"); wait(); } catch (Exception e) { } System.out.println("Lesen beginnt"); // schreibe Wert in den Puffer und setze 'leseindex' zyklisch um 1 weiter try { Thread.sleep(Basiswerte.lesedauer); } catch (Exception e) { } int gelesen = inhalt[leseindex]; leseindex = (leseindex+1)%(kap+1); System.out.println(" "+gelesen+" gelesen"); ausgabe(); System.out.println("Lesen endet"); // benachrichtige wartenden Thread (konkret: Erzeuger-Thread, der möglicherweise in 'schreibe()' wartet) notify(); return gelesen; } // Ende 'lies()' // 'leer()' ermittelt, ob der Puffer leer ist boolean leer() { return schreibindex == leseindex; } // 'voll()' ermittelt, ob der Puffer voll ist boolean voll() { return (schreibindex+1)%(kap+1) == leseindex; } // 'ausgabe()' gibt den Pufferinhalt auf den Bildschirm aus void ausgabe() { if (leseindex==schreibindex) { System.out.println(" Puffer leer"); return; } System.out.print(" Pufferinhalt:"); if (leseindex