Die bisher betrachteten Objekt-Sperren stellen den gegenseitigen Ausschluß beim Zugriff auf gemeinsam benutzte Daten sicher.
Aktiv zusammenarbeitende Threads müssen zusätzlich über Eigenschaften gemeinsam benutzter Ressourcen informiert sein.
Typisches Beispiel: Produzent/Konsument-Kommunikation
class Produzent extends Thread { private Puffer puffer; public Produzent(Puffer p) { puffer = p; } public void run() { for (int i = 0; i < 5; i++) { puffer.put(i); System.out.println ("Produzent gibt: " + i); try { sleep((int)(Math.random() * 1000)); } catch (InterruptedException e) {} } } }
class Konsument extends Thread { private Puffer puffer; public Konsument(Puffer p) { puffer = p; } public void run() { int wert = 0; for (int i = 0; i < 5; i++) { wert = puffer.get(); System.out.println ("Konsument nimmt " + wert); } } }
Das Hauptprogramm, das Produzent und Konsument startet:
class P_K_Test { public static void main(String[] args) { Puffer p = new Puffer(); new Produzent(p).start(); new Konsument(p).start(); } }
Annahme: Der benutzte Puffer kann genau eine Zahl aufnehmen:
Wenn Produzent und Konsument sich nicht über Eigenschaften der gemeinsam benutzten Ressource vom Typ Puffer verständigen, wird das Ergebnis falsch:
Die Synchronisation zwischen Produzent und Konsument geschieht in Java über Monitore.
Ein Thread im Monitor kann wait() aufrufen, um den Monitor freizugeben, während er auf eine bestimmte Bedingung wartet.
Die notify()- und notifyAll()-Methoden
Ein Thread im Monitor kann notifyAll() oder notify() aufrufen, um andere Threads, die wegen der gleichen Bedingungsvariable warten, wieder ausführbereit zu machen.
notifyAll macht alle wartenden Threads ausführbereit.
notify wählt aus den wartenden Threads einen aus, der ausführbereit wird.
Der Puffer für das Produzent/Konsument-Schema
class Puffer { // Pufferelement zwischen Produzent // und Konsument private int inhalt; private boolean gefüllt = false; public synchronized int get() { while (gefüllt == false) { try {wait();} catch (InterruptedException e) {} } gefüllt = false; notifyAll(); return inhalt; } public synchronized void put(int wert) { while (gefüllt == true) { try { wait();} catch (InterruptedException e) {} } inhalt = wert; gefüllt = true; notifyAll(); } }