Consumer Producer

Floffy

Mitglied
Hallo Leute.

Ich möchte das Consumer/Producer Problem anhand eines Supermarktes simulieren, also die Kasse ist der Consumer und der KundenGen der Producer, welcher Kunden - Objekte erzeugt.

Das Ganze funktioniert quasi auch, mein Problem ist nur das es so "abgehackt" läuft. Ich mein damit, z.B. dass der KundenGen sehr lange läuft und durchgehend 150 Kunden erzeugt, dann läuft die Kasse wieder lange und nimmt 100 Kunden weg ohne dass dazwischen der KundenGen wieder welche hinzufügen kann.

Meine Frage ist daher: Wie kann ich es ändern, dass die Threads jeweils nicht so lange laufen und sich öfter abwechseln, also zum Beispiel 4 Kunden hinzukommen, 1 gelöscht wird, 2 hinzukommen, 3 gelöscht werden usw.

Mein Main:
Code:
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        LinkedList<Kunde> warteschlange = new LinkedList();
        KundenGen producer = new KundenGen(warteschlange);
        Kasse consumer = new Kasse(warteschlange);
    }

}

Klasse Kunde:
Code:
public class Kunde {
    
    private static int lastID = 0;
    private int id;
    private float warenpreis;

    public Kunde() {
        this.id = this.nextID();
        this.einkaufen();
    }
    public int nextID() {
        return (lastID++);
    }
    public void einkaufen() {
        this.warenpreis = (float)Math.random()*10;
    }
    public int getId() {
        return this.id;
    }
}

KundenGen (Producer):
Code:
public class KundenGen extends Thread {
    
    private LinkedList<Kunde> warteschlange = null;
    boolean ende = false;
    
    public KundenGen(LinkedList<Kunde> w) {
        this.warteschlange = w;
        this.start();
    }
    public void run() {
        while(true) {
            synchronized(warteschlange) {
                try {
                    Kunde k = new Kunde();
                    warteschlange.addFirst(k);
                    warteschlange.notifyAll(); //Um andere Threads aufzuwecken die auf diese Liste warten
                    System.out.println("Neuer Kunde " + k.getId() + "! Anzahl der Kunden: " + warteschlange.size());
                    
                    
                    double faktor = Math.random()*100;
                    int wartezeit = (int)(Math.floor(faktor));
                    this.sleep(wartezeit);
                    
                    if (ende) {
                        break;
                    }
                } catch (InterruptedException ex) {
                    Logger.getLogger(KundenGen.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
    }
    public void beenden() {
        this.ende = true;
    }

}

Kasse (Consumer):
Code:
public class Kasse extends Thread {
    
    LinkedList<Kunde> warteschlange = null;
    boolean ende = false;
    
    public Kasse(LinkedList<Kunde> w) {
        this.warteschlange = w;
        this.start();
    }
    public void run() {
        while(true) {
            Kunde k = null;
            synchronized(warteschlange) {
                try {
                    while (warteschlange.size() == 0) {
                        try {
                            System.out.println("Kasse leer");
                            warteschlange.wait();
                        } catch (InterruptedException ex) {
                            System.out.println("CONSUMER INTERRUPTED");
                        }
                    }
                    k = warteschlange.removeLast();
                    warteschlange.notifyAll();
                    int len = warteschlange.size();
                    System.out.println("Kunde " + k.getId() + "entfernt! Anzahl der Kunden " + len);
                    
                    double faktor = Math.random()*100;
                    int wartezeit = (int)(Math.floor(faktor));
                    this.sleep(wartezeit);
                } catch (InterruptedException ex) {
                    Logger.getLogger(Kasse.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
            
            if(ende) break;
        }
    }
    public void beenden() {
        this.ende = true;
    }

}


Ich freue mich auf Rückmeldungen, Danke im Voraus :)
Grüße Flo
 

tim staeglich

Mitglied
Hi,

die klassische Methode wäre ein Thread Scheduling mit Semaphore.

Java bietet hier sogar Fairness Parameter an etc..

Wenn ich Zeit finde (sorry, knapp gerade) poste ich demnächst mal Beispielcode.

Grüße, Tim
 

takidoso

Erfahrenes Mitglied
Hi Floffy,
ich weiß, ich beantworte damit nicht Deine Frage und es ändert auch nix direkt an Deiner Verarbeitung, aber ich würde bezogen auf Deine Schleifen keine Endlosschleifen empfehlen, die dann mit break fluchtartig verlassen werden.
wie wäre es stattdessen mit sowas hier?
Code:
...
boolean ende = false

public void run()
{
   whlie (!ende)  // solange nicht beendet wurde
   {
     //hier wird was getan
   }
}
...
public void beenden() 
{
     this.ende = true;
}
Vorteil, Du kannst das ganze besser in eine Struktogramm bringen, wenn Du es müsstest ;-), ist damit in den allermeisten Fällen lesbarer.
Du sparst Dir jeweils die Fallunterscheidung für die Flucht aus der Schleife.
Ich weiß das kling jetzt Neunmalklug, doch in vielen Fällen kann Code mit fluchtartigen Verlassen von Schleifen unübersichtlich werden.
 

takidoso

Erfahrenes Mitglied
Soo und nun etws was mir bei Deiner Verarbeitung auffiel....
allerdings kann es sein, dass es quatsch ist was ich annehme.
hast Du schonmal versucht die sleep()-Mehtoden ohne this aufzurufen (kann mir zwar auch nicht vorstellen, dass dies ein unterschied machen sollte, wäre aber nur so eine Idee.

halt ... alles quark....
kann es sein, dass Dein synchronized dazu beiträgt dass alles synchron abläuft?
Denn KundenGen und Kasse teilen sich die selbe Warteschlange ...
Vielleicht solltest Du anstelle des notyfyAll() einfach nur die Synchronisierung "kürzer drehen", nämlich nur soweit wie es benötigt wird (also die Warteschlange geändert wird) und zwar bei beiden Warteschlangen manipulierenden Objekten.
Außerdem ist es vielleicht besser in der Kassen-Klasse anstelle einer Warteschleife, die auf die Größe der Warteschlange prüft nu reine Fallunterscheidung einzubauen und das wait ganz rausnehmen. Das vereinfacht den Code auf das wesentliche.
 
Zuletzt bearbeitet: