PP_SL/pp.A1-CondPhilosophers/src/main/java/pp/Philosopher.java

135 lines
3.3 KiB
Java
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

package pp;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.Condition;
import static pp.PhilosopherExperiment.*;
public class Philosopher extends Thread implements IPhilosopher {
private int seat;
private Philosopher left;
private Philosopher right;
private Lock table;
private Condition canEat;
private boolean eating = false;
private boolean stopped = false;
@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) {
this.seat = seat;
}
@Override
public void setTable(Lock table) {
// TODO Auto-generated method stub
this.table = table;
this.canEat = table.newCondition();
}
@Override
public void stopPhilosopher() {
// TODO Auto-generated method stub
this.stopped = true;
this.interrupt();
}
// Hauptlogik des Philosophen: Der Philosoph denkt, versucht zu essen, isst und beendet das Essen.
public void run() {
try {
while (!stopped) {
think(); // denkt eine Weile
beginEating(); // wartet, falls nötig, bis beide Nachbarn nicht essen
eat(); // isst eine zufällige Zeit
endEating(); // beendet das Essen und signalisiert Nachbarn
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
// Diese Methode wird aufgerufen, wenn der Philosoph mit dem Essen fertig ist.
// Sie setzt seinen Status zurück und signalisiert den Nachbarn, dass sie es nun versuchen können.
private void endEating() {
table.lock();
try {
eating = false;
log(seat, "hat fertig gegessen");
left.signal();
right.signal();
} finally {
table.unlock();
}
}
// Diese Methode simuliert das tatsächliche Essen mit einer zufälligen Dauer.
private void eat() throws InterruptedException {
Thread.sleep((long) (Math.random() * MAX_EATING_DURATION_MS));
}
// Diese Methode prüft, ob einer der Nachbarn gerade isst.
// Wenn ja, wartet dieser Philosoph auf seine Bedingung.
// Wenn beide frei sind, beginnt er zu essen.
private void beginEating() throws InterruptedException {
table.lock();
try {
while (left.eating || right.eating) {
log(seat, "wartet");
canEat.await(); // wartet, bis signal() von einem anderen Philosophen aufgerufen wird
}
eating = true;
log(seat, "isst jetzt");
} finally {
table.unlock();
}
}
// Der Philosoph denkt für eine gewisse Zeit (zufällig), danach signalisiert er den Nachbarn,
// dass er nun fertig ist mit Denken, was eventuell anderen hilft zu essen.
private void think() throws InterruptedException {
log(seat, "denkt");
Thread.sleep((long) (Math.random() * MAX_THINKING_DURATION_MS));
table.lock();
try {
left.signal();
right.signal();
} finally {
table.unlock();
}
}
// Diese Methode wird von anderen Philosophen aufgerufen,
// um diesen Philosophen zu wecken (z.B nach Ende einer Essensphase).
public void signal() {
table.lock();
try {
canEat.signal();
} finally {
table.unlock();
}
}
// Gibt zurück, ob dieser Philosoph aktuell isst wichtig für die Nachbarn.
// public boolean isEating() {
// return eating;
// }
}