[threading] wait/notify



  • A sei ein Thread, der den Monitor von einem Objekt X erlangt hat.
    Wird A nun in die wait Warteschleife versetzt, so wird der Monitor von X wieder freigegeben und andere Threads koennen eine notwendige Bedingung erfuellen, so dass A wieder mit notify() aktiviert werden kann und seine Arbeit fortsetzen kann.
    Die wait-Warteschleife laesst kein Zuordnung der einzelnen Threads zu(z.B. LIFO).
    Nun frage ich mich, woher der Aufruf von notify() "weiss", dass er genau den Thread A aus der Menge der wartenden Threads wieder aktivieren muss.
    notify(void) hat ja keinen Parameter, der einen gewuenschten Thread wieder freigibt.



  • A.notify() ?
    Bin mir aber nicht sicher ...





  • Folgendes Programm, das den wait/notify Mechanismus an Erzeuger/Verbraucher demonstriert. Ist der Puffer voll, muessen die Erzeuger warten(wait) und werden wieder geweckt(notify), wenn ein Verbraucher wieder einen Platz freigemacht hat.

    Wenn der Puffer leer ist, muessen die Verbraucher warten(wait) und werden wieder geweckt(notify), wenn ein Erzeuger ihn wieder auffuellt.

    Die relevanten Stellen sind fett und mit Kommentaren versehen.
    Vielleicht kann mir jemand diese Zeilen in Anbetracht meiner Anfangsfrage nochmal erklaeren.

    Schonmal vielen Dank im Voraus!

    [java]import java.util.Random;
    class Erzeuger extends Thread {
    private RingPuffer lager;

    Erzeuger( RingPuffer rp ){ lager = rp; }

    public void run(){
    while( true ){
    Produkt prd = new Produkt();
    try{
    sleep( prd.getProduktionsZeit() ); // "Produktionszeit"
    lager.ablegen( prd );
    } catch( InterruptedException e ){
    System.out.println("Unzulaessige Unterbrechung!");
    System.exit( 0 );
    }
    }
    }
    }

    class Verbraucher extends Thread {
    private RingPuffer lager;

    Verbraucher( RingPuffer rp ){ lager = rp; }

    public void run(){
    while( true ){
    try {
    Produkt prd = lager.holen();
    sleep( 500 ); // "Verbrauchszeit"
    } catch( InterruptedException e ){
    System.out.println("Unzulaessige Unterbrechung!");
    System.exit( 0 );
    }
    }
    }
    }

    class RingPuffer {
    private Produkt[] puffer;
    private int eingabeIndex, ausgabeIndex;
    private int pufferGroesse;
    private int gepuffert; // Anzahl gepufferter Elemente

    public RingPuffer( int groesse ){
    eingabeIndex = 0;
    ausgabeIndex = 0;
    gepuffert = 0;
    pufferGroesse = groesse;
    puffer = new Produkt[pufferGroesse];
    }

    public synchronized void ablegen( Produkt prd )
    throws InterruptedException {
    if( istVoll() ) wait();
    notify();
    // diese beiden Zeilen verstehe ich nicht...
    abspeichern( prd );
    System.out.println("Anzahl gepufferter Produkte: "+gepuffert );
    }

    public synchronized Produkt holen()
    throws InterruptedException {
    if( istLeer() ) wait();
    notify();
    //diese beiden Zeilen verstehe ich nicht....
    System.out.println("Anzahl gepufferter Produkte: "+(gepuffert-1) );
    return auslesen();
    }

    private synchronized boolean istVoll() {
    return gepuffert == pufferGroesse;
    }
    private synchronized boolean istLeer() {
    return gepuffert == 0;
    }
    private synchronized void abspeichern( Produkt prd ) {
    puffer[ eingabeIndex ] = prd;
    gepuffert++;
    eingabeIndex = (eingabeIndex+1) % pufferGroesse;
    }
    private synchronized Produkt auslesen() {
    Produkt prd = puffer[ ausgabeIndex ];
    gepuffert--;
    ausgabeIndex = (ausgabeIndex+1) % pufferGroesse;
    return prd;
    }
    }

    class Produkt {
    private static Random rg = new Random();
    private int produktionsZeit;
    Produkt() {
    int pz = rg.nextInt() % 1000;
    produktionsZeit = pz<0 ? -pz : pz ;
    }
    int getProduktionsZeit() { return produktionsZeit; }
    }

    public class ErzeugerVerbraucherTest {
    public static void main( String[] args ) {
    RingPuffer rpuf = new RingPuffer( 4 );
    Erzeuger e = new Erzeuger( rpuf );
    Verbraucher v = new Verbraucher( rpuf );
    e.start(); System.out.println("Erzeuger nimmt Arbeit auf");
    v.start(); System.out.println("Verbraucher nimmt Arbeit auf");
    }
    }[/java]



  • Ok, ich weiss nicht so ganz ob ich es verstanden habe, aber ich schreib mal was ich dazu denke:

    Die beiden Methoden die du nicht verstehst sind synchronized, d.h. es kann nur einen gleichzeitigen Zugriff darauf geben. Solange wait() ausgeführt wird hält das RingPuffer-Objekt den lock auf sich selbst. Versucht jetzt eine anderes Objekt darauf zuzugreifen erfolgt ein notify, dies weckt den Thread wieder auf und er schickt ein notify. Dabei wird einer der Threads die auf ein lock auf das Objekt warten benachrichtigt (bei notifyAll wären es alle).


Log in to reply