Benutzer-Werkzeuge

Webseiten-Werkzeuge


parallelism:producerconsumer:start

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen angezeigt.

Link zu dieser Vergleichsansicht

Beide Seiten der vorigen RevisionVorhergehende Überarbeitung
Nächste Überarbeitung
Vorhergehende Überarbeitung
parallelism:producerconsumer:start [2025/01/03 13:44] – [Passives Warten] Martin Pabstparallelism:producerconsumer:start [2025/03/04 09:03] (aktuell) – [Tidying up loose ends] Martin Pabst
Zeile 16: Zeile 16:
       * Falls "ja", legt er Ressourcen ab und benachrichtigt den Verbraucher. Falls dieser im Wartezustand ist, "wacht er auf".       * Falls "ja", legt er Ressourcen ab und benachrichtigt den Verbraucher. Falls dieser im Wartezustand ist, "wacht er auf".
       * Falls "nein", geht er in einen Wartezustand, der keine Systemressourcen verbraucht.       * Falls "nein", geht er in einen Wartezustand, der keine Systemressourcen verbraucht.
-    * Der Verbraucher seht nach, ob Ressourcen im Ablagebereich sind.+    * Der Verbraucher sieht nach, ob Ressourcen im Ablagebereich sind.
       * Falls "ja", nimmt er welche heraus und benachrichtigt den Erzeuger. Falls dieser im Wartezustand ist, "wacht er auf".       * Falls "ja", nimmt er welche heraus und benachrichtigt den Erzeuger. Falls dieser im Wartezustand ist, "wacht er auf".
       * Falls "nein", geht er in einen Wartezustand, der keine Systemressourcen verbraucht.       * Falls "nein", geht er in einen Wartezustand, der keine Systemressourcen verbraucht.
-Um passives Warten zu ermöglichen besitzt der Monitor die Methoden ''wait()'' (versetzt den aktuellen Thread in den Wartezustand) und ''notify()'' (holt einen der Wartenden Threads aus dem Wartezustand).+Um passives Warten zu ermöglichen besitzt der Monitor die Methoden ''wait()'' (versetzt den aktuellen Thread in den Wartezustand) und ''notify()'' (holt einen der wartenden Threads aus dem Wartezustand).
 </WRAP> </WRAP>
  
Zeile 45: Zeile 45:
    public void run() {    public void run() {
       while (anzahlPizzenTodo > 0) {       while (anzahlPizzenTodo > 0) {
-         SystemTools.pause(Random.randint(10, 100));+         Thread.sleep(Random.randint(10, 100));
          anzahlPizzenTodo -= tresen.legPizzaDrauf();          anzahlPizzenTodo -= tresen.legPizzaDrauf();
       }       }
Zeile 64: Zeile 64:
    public void run() {    public void run() {
       while (true) {       while (true) {
-         SystemTools.pause(Random.randint(10, 100));+         Thread.sleep(Random.randint(10, 100));
          anzahlPizzenServiert += tresen.holPizzaAb();          anzahlPizzenServiert += tresen.holPizzaAb();
          if(anzahlPizzenServiert % 10 == 0) {          if(anzahlPizzenServiert % 10 == 0) {
Zeile 183: Zeile 183:
          int timeSinceLastPizzaBaked = System.currentTimeMillis() - lastTimePizzaBaked;          int timeSinceLastPizzaBaked = System.currentTimeMillis() - lastTimePizzaBaked;
          if(timeSinceLastPizzaBaked < timeToBakeNextPizza) {          if(timeSinceLastPizzaBaked < timeToBakeNextPizza) {
-            SystemTools.pause(timeToBakeNextPizza - timeSinceLastPizzaBaked);+            Thread.sleep(timeToBakeNextPizza - timeSinceLastPizzaBaked);
             lastTimePizzaBaked = System.currentTimeMillis();             lastTimePizzaBaked = System.currentTimeMillis();
          }          }
Zeile 210: Zeile 210:
          }          }
          // Lisa bringt jetzt die Pizza zu den Kunden:          // Lisa bringt jetzt die Pizza zu den Kunden:
-         SystemTools.pause(Random.randint(10, 100)); +         Thread.sleep(Random.randint(10, 100)); 
       }       }
    }    }
Zeile 241: Zeile 241:
  
 </HTML> </HTML>
 +
 +==== Tidying up loose ends ====
  
 <WRAP center round tip 80%> <WRAP center round tip 80%>
 In den obigen Erklärungen wurden ein paar Sachverhalte vereinfacht, damit Sie das Prinzip des passiven Wartens gut verstehen können. Vielleicht sind Ihnen daher ein paar kleinere Ungereimtheiten aufgefallen. Es wird Zeit, sie jetzt im Detail zu klären! In den obigen Erklärungen wurden ein paar Sachverhalte vereinfacht, damit Sie das Prinzip des passiven Wartens gut verstehen können. Vielleicht sind Ihnen daher ein paar kleinere Ungereimtheiten aufgefallen. Es wird Zeit, sie jetzt im Detail zu klären!
-  * Solange es nur genau einen Erzeuger und genau einen Verbraucher gibt, könnte man statt der while-Loops in den Methoden ''legPizzaDrauf'' und ''holPizzaAb'' auch einfach nur if-statements verwenden. Sobald es mehrere Erzeuger/Verbraucher gibt, könnte es sein, dass ein Erzeuger durch das ''notify()'' eines anderen Erzeugers "aufgeweckt" wurde... \\ In der Praxis könnte man in so einem Fall aber - noch besser - zwei unterschiedliche Monitore für Verbraucher und Erzeuger verwenden, siehe die Aufgabe unten+  * Solange es nur **genau einen Erzeuger und genau einen Verbraucher** gibt, könnte man statt der while-Loops in den Methoden ''legPizzaDrauf'' und ''holPizzaAb'' auch einfach nur if-statements verwenden. Sobald es **mehrere Erzeuger/Verbraucher** gibt, könnte es aber sein, dass ein **Erzeuger** durch das ''notify()'' eines anderen **Erzeugers** "aufgeweckt" wurde. In diesem Fall ist dann die ''while-loop'' unverzichtbar, da der Erzeuger "aufgeweckt" wurde ohne dass ein freier Platz im Austauschbereich geschaffen worden war. \\ In der Praxis könnte man in so einem Fall aber - noch besser - zwei unterschiedliche Monitore für Verbraucher und Erzeuger verwenden. 
-  * In den obigen Erklärungen wurde vereinfachend so getan, also ob der Aufruf von ''notify()'' durch den Erzeuger direkt den Verbraucher "aufweckt", so dass dieser **sofort** mit der Abarbeitung der Anweisung fortfährt, die auf die ''wait()''-Anweisung folgt. Aber dann wären ja Erzeuger als auch Verbraucher **gleichzeitig in der synchronized-Methode**! Nach dem ''notify()'' könnten ja noch weitere Anweisungen in der ''synchronized''-Methode stehen\\ \\ In der Tat sind die Abläufe in der Realität noch etwas komplizierter. Jeder Thread in Java hat einen Zustand (//thread state//), der die Werte //new//, //runnable//, //running//, //waiting// und //terminated// annehmen kann. Nur im Zustand //running// werden die Anweisungen des Threads ausgeführt. +  * In den obigen Erklärungen wurde vereinfachend so getan, also ob der Aufruf von ''notify()'' durch den Erzeuger direkt den Verbraucher "aufweckt" (und umgekehrt), so dass letzterer **sofort** mit der Abarbeitung der Anweisung fortfährt, die auf die ''wait()''-Anweisung folgt. Aber dann wären ja sowohl Erzeuger als auch Verbraucher **gleichzeitig in der synchronized-Methode**! Das **darf nicht sein**, denn nach dem ''notify()'' könnten ja ohne Weiteres noch weitere Anweisungen in der ''synchronized''-Methode stehen.:-/ \\ \\ In der Tat sind die Abläufe in der Realität etwas komplexer. Jeder Thread in Java hat einen Zustand (//thread state//), der die Werte //new//, //runnable//, //running//, //waiting// und //terminated// annehmen kann. Nur im Zustand //running// werden die Anweisungen des Threads ausgeführt. 
 {{ :parallelism:producerconsumer:java-threadstates.svg?600 |}} {{ :parallelism:producerconsumer:java-threadstates.svg?600 |}}
   * Durch den Aufruf von //wait()// des Monitor-Objekts geht der Thread in den Zustand //waiting// über. Wird später irgendwann die Methode //notify()// des Monitor-Objekts aufgerufen, so geht einer der aktuell für diesen Monitor wartenden Threads in den Zustand //runnable// über, **nicht jedoch in den Zustand running**! Erst, wenn **alle kritischen Bereiche** des Monitors vom letzten Thread verlassen wurden, wird einer der Threads vom Zustand ''runnable'' in den Zustand ''running'' versetzt und setzt seine Ausführung fort.    * Durch den Aufruf von //wait()// des Monitor-Objekts geht der Thread in den Zustand //waiting// über. Wird später irgendwann die Methode //notify()// des Monitor-Objekts aufgerufen, so geht einer der aktuell für diesen Monitor wartenden Threads in den Zustand //runnable// über, **nicht jedoch in den Zustand running**! Erst, wenn **alle kritischen Bereiche** des Monitors vom letzten Thread verlassen wurden, wird einer der Threads vom Zustand ''runnable'' in den Zustand ''running'' versetzt und setzt seine Ausführung fort. 
Zeile 252: Zeile 254:
     * führt eine Liste aller ihm zugeordneten Threads im Zustand ''waiting'' und      * führt eine Liste aller ihm zugeordneten Threads im Zustand ''waiting'' und 
     * eine Liste aller ihm zugeordneten Threads im Zustand ''runnable''.     * eine Liste aller ihm zugeordneten Threads im Zustand ''runnable''.
 +</WRAP>
 +
 +===== Aufgaben =====
 +==== Aufgabe 1 ====
 +<WRAP center round todo 80%>
 +Erweitern Sie den obigen Algorithmus zum passiven Warten so, dass es 10 Producer und 10 Verbraucher gibt und die Kapazität des Tresens erhöht werden kann (z.B. auf 3 Pizzen). \\ Sie werden dazu die Aufrufe von ''notify()'' durch ''notifyAll()'' ersetzen müssen. Erklären Sie, weshalb dies nötig ist und welchen Nachteil es mit sich bringt. \\ \\ 
 +[[.aufgabe1loesung:start|Lösung]]
 </WRAP> </WRAP>
  
  
parallelism/producerconsumer/start.1735911895.txt.gz · Zuletzt geändert: 2025/01/03 13:44 von Martin Pabst

Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki