diff --git a/src/main/java/io/dama/ffi/parcoord/dining/cond/IPhilosopher.java b/src/main/java/io/dama/ffi/parcoord/dining/cond/IPhilosopher.java index 420b223..4b53bd0 100644 --- a/src/main/java/io/dama/ffi/parcoord/dining/cond/IPhilosopher.java +++ b/src/main/java/io/dama/ffi/parcoord/dining/cond/IPhilosopher.java @@ -4,6 +4,7 @@ import java.util.concurrent.locks.Lock; public interface IPhilosopher { + void run(); void setLeft(IPhilosopher left); diff --git a/src/main/java/io/dama/ffi/parcoord/dining/cond/Philosopher.java b/src/main/java/io/dama/ffi/parcoord/dining/cond/Philosopher.java index 03801b8..0c468c1 100644 --- a/src/main/java/io/dama/ffi/parcoord/dining/cond/Philosopher.java +++ b/src/main/java/io/dama/ffi/parcoord/dining/cond/Philosopher.java @@ -1,36 +1,116 @@ package io.dama.ffi.parcoord.dining.cond; +import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; +/** + * Bauen Sie die (synchronisierten) dinierenden Philosophen um, so dass Bedingungsvariablen benutzt werden: + *

+ * - Jeder Philosoph ist ein Thread und besitzt einen Warteraum, in dem die Nachbarphilosophen darauf warten, dass er seine + * Stäbchen freigibt. + * - Der Name der Klasse muss io.dama.ffi.parcoord.dining.cond.Philosopher sein. + * - Philosoph implementiert das Interface io.dama.ffi.parcoord.dining.cond.IPhilosopher + * - Jeder Philosoph hat je eine Referenz auf seinen linken und rechten Nachbarn. setLeft(IPhilosopher left); setRight( + * IPhilosopher right); + * - Der Tisch wird durch ein ReentrantLock-Objekt (Interface Lock) repräsentiert. Alle Philosophen müssen den Tisch + * verwenden, wenn sie beginnen zu essen. Eine Referenz auf den Tisch kann mit dem Setter übergeben werden: setTable(Lock + * table); + * - Möchte ein Philosoph beginnen zu essen, prüft er, ob sein linker Nachbar oder sein rechter Nachbar isst; er erwartet + * den Moment, in dem beide nicht essen. Dann beginnt er zu essen. + * - Wenn ein Philosoph denkt, isst er nicht und signalisiert jeweils seinem linken Nachbarn und seinem rechten Nachbarn, + * dass er nicht isst. + */ public class Philosopher extends Thread implements IPhilosopher { + private Philosopher left; + private Philosopher right; + + private int seat; + private Lock table; + private Condition condition; + + private boolean stop = false; + private boolean isEating = false; + + private void log(String message) { + synchronized (Philosopher.class) { + for (var i = 1; i <= this.seat; i++) { + System.out.print(" ".repeat(40)); + } + System.out.println(message); + } + } @Override public void setLeft(IPhilosopher left) { - // TODO Auto-generated method stub - // Cast auf Philosopher erforderlich + this.left = (Philosopher) left; } @Override public void setRight(IPhilosopher right) { - // TODO Auto-generated method stub - // Cast auf Philosopher erforderlich + this.right = (Philosopher) right; } @Override public void setSeat(int seat) { - // TODO Auto-generated method stub - + this.seat = seat; } @Override public void setTable(Lock table) { - // TODO Auto-generated method stub - + this.table = table; + this.condition = table.newCondition(); } @Override public void stopPhilosopher() { - // TODO Auto-generated method stub + log("Philosopher " + seat + " is stopping"); + this.stop = true; + } + @Override + public void run() { + while (!this.stop) { + this.sleepRandomDuration(PhilosopherExperiment.MAX_THINKING_DURATION_MS); + + try { + this.table.lock(); + while (this.left.isEating || this.right.isEating) { + log("Philosopher " + seat + " is waiting for his neighbors to finish eating"); + this.left.condition.await(); + this.right.condition.await(); + } + + this.isEating = true; + + log("Philosopher " + seat + " is taking chopsticks"); + + this.sleepRandomDuration(PhilosopherExperiment.MAX_TAKING_TIME_MS); + log("Philosopher " + seat + " is eating"); + + this.sleepRandomDuration(PhilosopherExperiment.MAX_EATING_DURATION_MS); + log("Philosopher " + seat + " is done eating"); + + this.isEating = false; + + } catch (InterruptedException e) { + log("Philosopher " + seat + " was interrupted"); + throw new RuntimeException(e); + } finally { + this.condition.signalAll(); + this.table.unlock(); + } + } + + log("Philosopher " + seat + " has stopped"); + } + + private void sleepRandomDuration(int max) { + try { + final int duration = (int) (Math.random() * max); + log("Philosopher " + seat + " is occupied for " + duration + "ms"); + Thread.sleep(duration); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } } diff --git a/src/main/java/io/dama/ffi/parcoord/dining/cond/PhilosopherExperiment.java b/src/main/java/io/dama/ffi/parcoord/dining/cond/PhilosopherExperiment.java index 2cc1bdd..6b4001f 100644 --- a/src/main/java/io/dama/ffi/parcoord/dining/cond/PhilosopherExperiment.java +++ b/src/main/java/io/dama/ffi/parcoord/dining/cond/PhilosopherExperiment.java @@ -3,33 +3,39 @@ package io.dama.ffi.parcoord.dining.cond; import java.util.concurrent.locks.ReentrantLock; public class PhilosopherExperiment { - static final int MAX_THINKING_DURATION_MS = 3000; - static final int MAX_EATING_DURATION_MS = 3000; - static final int MAX_TAKING_TIME_MS = 100; + + static final int MAX_THINKING_DURATION_MS = 3000; // 3000 + static final int MAX_EATING_DURATION_MS = 3000; // 3000 + static final int MAX_TAKING_TIME_MS = 100; // 100 static final int PHILOSOPHER_NUM = 5; static final int EXP_DURATION_MS = 20000; + static IPhilosopher[] philosophers = new Philosopher[PHILOSOPHER_NUM]; public static void main(String... args) throws InterruptedException { var table = new ReentrantLock(); + for (var i = 0; i < PHILOSOPHER_NUM; i++) { philosophers[i] = new Philosopher(); philosophers[i].setTable(table); philosophers[i].setSeat(i); } + philosophers[0].setLeft(philosophers[PHILOSOPHER_NUM - 1]); philosophers[0].setRight(philosophers[1]); for (var i = 1; i < (PHILOSOPHER_NUM - 1); i++) { philosophers[i].setLeft(philosophers[i - 1]); philosophers[i].setRight(philosophers[i + 1]); } - philosophers[PHILOSOPHER_NUM - 1] - .setLeft(philosophers[PHILOSOPHER_NUM - 2]); + philosophers[PHILOSOPHER_NUM - 1].setLeft(philosophers[PHILOSOPHER_NUM - 2]); philosophers[PHILOSOPHER_NUM - 1].setRight(philosophers[0]); + for (var i = 0; i < PHILOSOPHER_NUM; i++) { philosophers[i].start(); } + Thread.sleep(EXP_DURATION_MS); + for (var i = 0; i < PHILOSOPHER_NUM; i++) { philosophers[i].stopPhilosopher(); }