/*************************************************************/ /* Prof. Dr. Carsten Vogt */ /* FH Koeln, Fak. 07 / Nachrichtentechnik */ /* http://www.nt.fh-koeln.de/vogt */ /* */ /* wait(), notify(): */ /* Ein Objekt bietet zwei Methoden an, wobei sichergestellt */ /* wird, dass zunaechst die eine und erst dann die andere */ /* ausgefuehrt wird. */ /*************************************************************/ class SynchronObjekt { /* Objekt, das u.a. zwei Methoden "zuerst()" und "spaeter()" anbietet. Es wird durchgesetzt, dass "spaeter()" nicht vor "zuerst()" ausgefuehrt wird. */ boolean fertig; /* gibt an, ob "zuerst()" schon ausgefuehrt wurde. */ /* Konstruktor: setzt "fertig" auf false */ SynchronObjekt() { fertig = false; } /* Die folgende Methode "warte()" versetzt den aufrufenden Thread in den Wartezustand, solange "fertig" false ist. Der Uebergang in den Wartezustand erfolgt durch wait(); wait() muss in einer als synchronized deklarierten Methode eines Objekts benutzt werden. Die Benutzung einer while-Schleife, um die Wartebedingung zu testen, ist guter Programmierstil. Es kann durchaus vorkommen (wenn auch nicht in dieser speziellen Anwendung), dass ein Thread geweckt wird, ohne dass die spezielle Be- dingung, auf die er eigentlich wartet, erfuellt ist. Er sollte sie daher nochmals testen und ggf. erneut in den Wartezustand uebergehen. */ synchronized void warte() { while (!fertig) { try { wait(); /* wait() blockiert den aufrufenden Thread (in diesem Pro- gramm den, der "spaeter()" ausfuehrt) so lange, bis ein anderer Thread in einer anderen Methode dieses Objekts notify() oder notifyAll() aufruft. Das ist in diesem Fall der Thread, der die Methode "zuerst()" ausfuehrt. */ } catch (InterruptedException E) { } } } /* Die Methode "fertig()" signalisiert, dass die erste Methode "zuerst()" beendet ist. Dies geschieht durch notify(), das wie wait() in einer als synchronized deklarierten Methode benutzt werden muss. */ synchronized void fertig() { fertig = true; /* Benachrichtige per notify() einen wartenden Thread - in diesem Programm den, der in "spaeter()" und "warte()" blockiert ist. */ notify(); } /* zuerst(): Methode, die als erste auf dem Objekt ausgefuehrt werden soll */ void zuerst(Thread t) { System.out.println("Methode 1: Beginn"); /* Ausfuehrungszeit: ca. 2 Sekunden */ try { t.sleep(2000); } catch (InterruptedException E) { } System.out.println("Methode 1: Ende"); /* Signalisierung, dass erste Methode beendet ist */ fertig(); } /* spaeter(): Methode, die als zweite auf dem Objekt ausgefuehrt werden soll */ void spaeter(Thread t) { try { System.out.println("Methode 2: Beginn mit Wartezustand"); /* Abwarten, bis erste Methode beendet */ warte(); System.out.println("Methode 2: Wartezustand verlassen"); /* Ausfuehrungszeit: ca. 2 Sekunden */ t.sleep(2000); System.out.println("Methode 2: Ende"); } catch (InterruptedException E) { } } } /* Thread, der die erste Methode aufruft */ class Vorgaenger extends Thread { private SynchronObjekt obj; Vorgaenger(SynchronObjekt o) { obj = o; } public void run() { try { /* Erst 2 Sekunden warten ... */ sleep(2000); } catch (InterruptedException E) { } /* ... und dann die Methode "zuerst()" aufrufen */ obj.zuerst(this); } } /* Thread, der die zweite Methode aufruft */ class Nachfolger extends Thread { private SynchronObjekt obj; Nachfolger(SynchronObjekt o) { obj = o; } public void run() { /* sofort die Methode "spaeter()" aufrufen */ obj.spaeter(this); } } public class WaitNotify2 { /* Hauptprogramm */ public static void main(String[] args) { System.out.println(); /* sobj ist das Objekt, dessen Methoden aufgerufen werden sollen. Es wird an die Konstruktoren der beiden Threads uebergeben. */ SynchronObjekt sobj = new SynchronObjekt(); Vorgaenger t1 = new Vorgaenger(sobj); Nachfolger t2 = new Nachfolger(sobj); /* Threads werden gestartet. Obwohl t1 zunaechst um zwei Sekunden verzoegert wird (siehe Class "Vorgaenger" oben), fuehrt er als erster seine Methode aus. */ t1.start(); t2.start(); } }