From b943a4d3ad5b152bc7587a30ee1c647a7decabc0 Mon Sep 17 00:00:00 2001 From: Obai Albek <89144251+ObaiAlbek@users.noreply.github.com> Date: Thu, 28 Aug 2025 14:01:26 +0200 Subject: [PATCH] Dining Philosophers project --- CondPhilosophers/.gitignore | 3 + CondPhilosophers/pom.xml | 61 ++++++++ .../src/main/java/pp/IPhilosopher.java | 30 ++++ .../src/main/java/pp/Philosopher.java | 138 ++++++++++++++++++ .../main/java/pp/PhilosopherExperiment.java | 37 +++++ README.md | 19 +++ 6 files changed, 288 insertions(+) create mode 100644 CondPhilosophers/.gitignore create mode 100644 CondPhilosophers/pom.xml create mode 100644 CondPhilosophers/src/main/java/pp/IPhilosopher.java create mode 100644 CondPhilosophers/src/main/java/pp/Philosopher.java create mode 100644 CondPhilosophers/src/main/java/pp/PhilosopherExperiment.java create mode 100644 README.md diff --git a/CondPhilosophers/.gitignore b/CondPhilosophers/.gitignore new file mode 100644 index 0000000..525681c --- /dev/null +++ b/CondPhilosophers/.gitignore @@ -0,0 +1,3 @@ +/target/ +/.classpath +/.project diff --git a/CondPhilosophers/pom.xml b/CondPhilosophers/pom.xml new file mode 100644 index 0000000..4fcff74 --- /dev/null +++ b/CondPhilosophers/pom.xml @@ -0,0 +1,61 @@ + + 4.0.0 + pp + pp.A1-CondPhilosophers + 1.0-SNAPSHOT + jar + + + pp.PhilosopherExperiment + 10 + UTF-8 + + + + org.junit.jupiter + junit-jupiter + 5.10.0 + test + + + org.projectlombok + lombok + 1.18.30 + provided + + + net.jcip + jcip-annotations + 1.0 + provided + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0 + + + org.apache.maven.plugins + maven-compiler-plugin + 3.9.0 + + + org.codehaus.mojo + exec-maven-plugin + 3.1.0 + + + org.apache.maven.plugins + maven-javadoc-plugin + 3.5.0 + + private + en_US + + + + + diff --git a/CondPhilosophers/src/main/java/pp/IPhilosopher.java b/CondPhilosophers/src/main/java/pp/IPhilosopher.java new file mode 100644 index 0000000..edb96c8 --- /dev/null +++ b/CondPhilosophers/src/main/java/pp/IPhilosopher.java @@ -0,0 +1,30 @@ +package pp; + +import java.util.concurrent.locks.Lock; + +public interface IPhilosopher { + + void run(); + + void setLeft(IPhilosopher left); + + void setRight(IPhilosopher right); + + void setSeat(int seat); + + void setTable(Lock table); + + void start(); + + void stopPhilosopher(); + + default void log(int seat, String message) { + synchronized (Philosopher.class) { + for (var i = 1; i <= seat; i++) { + System.out.print(" "); + } + System.out.println("P" + seat + ": " + message); + } + } + +} diff --git a/CondPhilosophers/src/main/java/pp/Philosopher.java b/CondPhilosophers/src/main/java/pp/Philosopher.java new file mode 100644 index 0000000..df328c9 --- /dev/null +++ b/CondPhilosophers/src/main/java/pp/Philosopher.java @@ -0,0 +1,138 @@ +package pp; + +import java.util.Random; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; + +public class Philosopher extends Thread implements IPhilosopher { + private int seat; + private Philosopher rechts; + private Philosopher links; + private Lock table; + private Condition canEat; + private volatile boolean stopped; + private volatile boolean eating; + private final Random random; + + public Philosopher() { + this.random = new Random(); + this.seat = 0; + this.stopped = false; + } + + + + @Override + public void run() { + try { + while (!this.stopped) { + think(); + eat(); + } + } catch (InterruptedException e) { + } + log(seat,"beendet"); + } + + private void eat() throws InterruptedException { + this.table.lock(); + try { + + while (this.links.eating || this.rechts.eating) { + log(seat,"warten!"); + this.canEat.await(); + } + this.eating = true; + log(seat, " : isst gerade!"); + } finally { + table.unlock(); + } + Thread.sleep(this.random.nextInt(PhilosopherExperiment.MAX_EATING_DURATION_MS)); + } + + private void think() throws InterruptedException { + this.table.lock(); + + try { + if (this.eating) + this.eating = false; + this.links.canEat.signal(); + this.rechts.canEat.signal(); + log(seat,"denken"); + + } finally { + this.table.unlock(); + } + + Thread.sleep(random.nextInt(PhilosopherExperiment.MAX_THINKING_DURATION_MS)); + + } + + @Override + public void setLeft(IPhilosopher left) { + // TODO Auto-generated method stub + // Cast auf Philosopher erforderlich + this.links = (Philosopher) left; + } + + @Override + public void setRight(IPhilosopher right) { + // TODO Auto-generated method stub + // Cast auf Philosopher erforderlich + this.rechts = (Philosopher) right; + } + + @Override + public void setSeat(int seat) { + this.seat = seat; + } + + @Override + public void setTable(Lock table) { + // TODO Auto-generated method stub + this.table = table; + canEat = this.table.newCondition(); + + } + + @Override + public void stopPhilosopher() { + this.stopped = true; + interrupt(); + } + + public static void main(String[] args) throws InterruptedException { + int numPhilosophers = 5; + Lock table = new ReentrantLock(); + Philosopher[] philosophers = new Philosopher[numPhilosophers]; + + for (int i = 0; i < numPhilosophers; i++) { + philosophers[i] = new Philosopher(); + philosophers[i].setSeat(i); + philosophers[i].setTable(table); + } + + for (int i = 0; i < numPhilosophers; i++) { + philosophers[i].setLeft(philosophers[(i + numPhilosophers - 1) % numPhilosophers]); + philosophers[i].setRight(philosophers[(i + 1) % numPhilosophers]); + } + + for (Philosopher p : philosophers) { + p.start(); + } + + Thread.sleep(10_000); // Laufzeit: 10 Sekunden + + for (Philosopher p : philosophers) { + p.stopPhilosopher(); + } + + for (Philosopher p : philosophers) { + p.join(); + } + + System.out.println("Experiment beendet!"); + } + +} diff --git a/CondPhilosophers/src/main/java/pp/PhilosopherExperiment.java b/CondPhilosophers/src/main/java/pp/PhilosopherExperiment.java new file mode 100644 index 0000000..ad68ed4 --- /dev/null +++ b/CondPhilosophers/src/main/java/pp/PhilosopherExperiment.java @@ -0,0 +1,37 @@ +package pp; + +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 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].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(); + } + } +} diff --git a/README.md b/README.md new file mode 100644 index 0000000..6bf27f7 --- /dev/null +++ b/README.md @@ -0,0 +1,19 @@ +# Dining Philosophers (Java) + +## Projektbeschreibung +Dieses Projekt implementiert das klassische **Dining-Philosophers-Problem** in Java. +Es zeigt, wie mehrere Threads gleichzeitig arbeiten und dabei über **Locks und Conditions** synchronisiert werden, um Deadlocks zu vermeiden. + +## Projektstruktur +- `IPhilosopher.java` – Interface für Philosophen +- `Philosopher.java` – Implementierung eines Philosophen als Thread +- `PhilosopherExperiment.java` – Startklasse für die Simulation + +## Technologien +- Java (Threads, Locks, Conditions) +- Maven (Build- und Projektverwaltung) + +## Ausführen +1. Mit Maven bauen: + ```bash + mvn clean install