Skip to content

Dining Philosophers (Speisende Philosophen)

Folgende Philosophen könnnen dargestellt werden.

Bild Name Farbe3 Geburt Tod
Aquin #2a3234 12251 1274
Aristoteles #0fa0e3 -3842 -322
Augustinus #ffb61c 354 430
Averroes #dac66e 1126 1198
Bacon #377296 1561 1626
Buddha #ff7a18 -563 -483
Descartes #1f2628 1596 1650
Hegel #7f5437 1770 1831
Hume #f7333f 1711 1776
Jesus #fa323f -4 30
Kant #767733 1724 1804
Kierkegaard #471008 1813 1855
Konfuzius #8b101d -551 -479
Laozi #114ea6 -600 -550
Machiavelli #f7323d 1469 1527
Marx #1b2223 1818 1883
Montesquieu #87111b 1689 1755
Nietzsche #293133 1844 1900
Platon #bda8d3 -427 -348
Rousseau #3c7eaa 1712 1778
Schopenhauer #323835 1788 1860
Seneca #dde1de 1 65
Sokrates #f3a05b -469 -399
Thales #0fa2e3 -623 -548
Unamuno #232a2c 1864 1936
Voltaire #4b2c62 1694 1778

/*
 * Engine Pi ist eine anfängerorientierte 2D-Gaming Engine.
 *
 * Copyright (c) 2026 Josef Friedrich and contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package demos.edu_projects.concurrency.philosophers;

import java.util.Random;

import pi.Controller;
import pi.annotations.Getter;
import pi.annotations.Setter;

// Go to file:///data/school/repos/inf/java/engine-pi/docs/manual/projects/philosophers.md

/**
 * Ein speisender Philosoph.
 *
 * @author Johannes Neumeyer
 * @author Josef Friedrich
 *
 * @version 1.0
 */
class Philosopher extends Thread
{
    /**
     * Die Zeitangabe in ms als Grundlage für die Bestimmung zufälliger Ess- und
     * Wartezeiten.
     */
    private int waitingTime;

    /**
     * Der Zufallsgenerator.
     */
    private Random random;

    /**
     * Der Zeitpunkt, an dem der Philosoph zuletzt gegessen hat.
     */
    private long lastMeal;

    /**
     * Konstruktor für Objekte der Klasse Philosoph.
     *
     * @param color Die Farbe des Tellers.
     * @param left Die linke Gabel, die der Philosoph nutzt.
     * @param right Die rechte Gabel, die der Philosoph nutzt.
     */
    Philosopher(String name, String color, int birth, int death)
    {
        waitingTime = 50;
        this.name = name;
        this.color = color;
        this.birth = birth;
        this.death = death;
        random = new Random();
    }

    /* forks */

    /**
     * Die linke Gabel.
     */
    private Fork leftFork;

    /**
     * Die rechte Gabel.
     */
    private Fork rightFork;

    /**
     * Setzt die beiden Gabeln.
     *
     * @param left Die linke Gabel.
     * @param right Die rechte Gabel.
     */
    @Setter
    public void forks(Fork left, Fork right)
    {
        leftFork = left;
        rightFork = right;
    }

    /**
     * Der <b>Name</b> des Philosophen.
     */
    private String name;

    /**
     *
     * @return
     */
    @Getter
    public String name()
    {
        return name;
    }

    /* color */

    /**
     * Die Farbe des Tellers.
     */
    private String color;

    @Getter
    public String color()
    {
        return color;
    }

    /* lifeTime */

    /**
     * Das <b>Geburstsjahr</b> des Philosophen.
     *
     * <p>
     * Jahre vor Christi Geburt werden als Minuszahlen dargestellt.
     * </p>
     */
    private int birth;

    /**
     * Das <b>Sterbejahr</b> des Philosophen.
     *
     * <p>
     * Jahre vor Christi Geburt werden als Minuszahlen dargestellt. Dieses
     * Attribut ist nur der Vollständigkeit halber hier aufgeführt.
     * </p>
     */
    private int death;

    @Getter
    public String lifeTime()
    {
        if (birth < 0 && death < 0)
        {
            return -birth + " - " + -death + " v. Chr.";
        }
        if (birth < 0)
        {
            return -birth + " v. Chr. - " + death;
        }
        return birth + " - " + death;
    }

    /**
     * Gibt den Zeitpunkt aus, an dem der Philosoph zuletzt gegessen hat.
     *
     * @return Der Zeitpunkt, an dem der Philosoph zuletzt gegessen hat.
     */
    @Getter
    public long lastMeal()
    {
        return lastMeal;
    }

    /**
     * Gibt das Geburtsjahr des Philosophen aus.
     *
     * @return Das Geburtsjahr des Philosophen.
     */
    @Getter
    public int birth()
    {
        return birth;
    }

    /**
     * Gibt den Zeitpunkt aus, an dem der Philosoph zuletzt gegessen hat.
     *
     * @return Der Zeitpunkt, an dem der Philosoph zuletzt gegessen hat.
     */
    public boolean isStarving()
    {
        return System.currentTimeMillis() - lastMeal > 200;
    }

    /**
     * Der Philosoph wartet eine zufällig Zeit lang.
     */
    private void waitRandomly()
    {
        try
        {
            sleep(random.nextInt(waitingTime));
        }
        catch (InterruptedException e)
        {
            Thread.currentThread().interrupt();
        }
    }

    /**
     * Der Philosoph denkt.
     */
    private void think()
    {
        waitRandomly();
    }

    /**
     * Der Philosoph isst.
     */
    private void eat()
    {
        waitRandomly();
        lastMeal = System.currentTimeMillis();
        eatCounter++;
    }

    /**
     * Wie oft die Philosophen bereits gegessen haben.
     */
    private int eatCounter;

    public int eatCounter()
    {
        return eatCounter;
    }

    /**
     * Erfülle alle Coffman-Bedingungen.
     */
    public void fullfilCoffman()
    {
        // denken
        think();

        // essen
        leftFork.pickUp(color);
        rightFork.pickUp(color);
        eat();
        leftFork.putDown();
        rightFork.putDown();
    }

    /**
     * Verletzte die Coffman-Bedingung 4 („Zyklisches Warten”)
     */
    public void violateCoffman4()
    {
        // denken
        think();

        // essen
        leftFork.pickUp(color);
        if (rightFork.id() > leftFork.id())
        {
            rightFork.pickUp(color);
        }
        else
        {
            leftFork.putDown();
            rightFork.pickUp(color);
            leftFork.pickUp(color);
        }
        eat();
        leftFork.putDown();
        rightFork.putDown();
    }

    /**
     * Verletze die Coffman-Bedingung 2 („Halten und Warten“)
     */
    public void violateCoffman2()
    {
        // denken
        think();

        // essen
        leftFork.pickUp(color);
        if (rightFork.tryPickUp(color))
        {
            eat();
            rightFork.putDown();
        }
        leftFork.putDown();
    }

    /**
     * Die Arbeitsmethode des Threads mit einer Endlosschleife: Der Philosoph
     * nimmt nach einer Zeit des Denkens die Gabeln auf, isst und legt sie dann
     * wieder ab.
     */
    @Override
    public void run()
    {
        while (true)
        {
            fullfilCoffman();
            // violateCoffman4();
            // violateCoffman2();
        }
    }

    public static void main(String[] args)
    {
        Controller.instantMode(false);
        Controller.start(new DiningPhilosophers(5), 800, 800);
    }
}
Zum Java-Code: demos//home/runner/work/engine-pi/engine-pi/subprojects/demos/src/main/java/demos/edu_projects/concurrency/philosophers/Philosopher.java

/*
 * Engine Pi ist eine anfängerorientierte 2D-Gaming Engine.
 *
 * Copyright (c) 2026 Josef Friedrich and contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package demos.edu_projects.concurrency.philosophers;

import pi.Controller;
import pi.actor.Line;

// Go to file:///data/school/repos/inf/java/engine-pi/docs/manual/projects/philosophers.md

/**
 * Die Gabel zwischen zwei Philosophen.
 *
 * @author Johannes Neumeyer
 * @author Josef Friedrich
 *
 * @version 1.0
 */
class Fork
{
    /**
     * Gibt an, ob die Gabel aktuell benutzt wird.
     */
    private boolean used;

    /**
     * Die Darstellung der Gabel als Linie.
     */
    private Line line;

    /**
     * Konstruktor für Objekte der Klasse Gabel
     *
     * @param id Die ID der Gabel.
     * @param line Die Darstellung der Gabel als Linie.
     */
    Fork(int id, Line line)
    {
        used = false;
        this.line = line;
        this.id = id;
    }

    /* id */

    /**
     * Die ID der Gabel.
     */
    private int id;

    /**
     * Liefert die ID der Gabel.
     *
     * @return Die ID der Gabel.
     */
    int id()
    {
        return id;
    }

    /**
     * Es wird gewartet, bis die Gabel nicht mehr in Benutzung ist; dann wird
     * sie aufgenommen.
     *
     * @param color Die Farbe des Philosophen, der die Gabel aufnehmen möchte;
     *     die Gabel wird dann auf diese Farbe gesetzt.
     */
    synchronized void pickUp(String color)
    {
        while (used)
        {
            try
            {
                wait();
            }
            catch (InterruptedException e)
            {
                Thread.currentThread().interrupt();
            }
        }
        used = true;
        line.color(color);
    }

    /**
     * Es wird mit kurzen Wartepausen immer wieder versucht, eine Gabel
     * aufzunehmen. Gelingt dies nicht, wird die Methode nach maximal 100
     * Versuchen beendet.
     *
     * @param color Die Farbe des Philosophen, der die Gabel aufnehmen möchte;
     *     die Gabel wird bei erfolgreicher Aufnahme auf diese Farbe gesetzt.
     */
    synchronized boolean tryPickUp(String color)
    {
        int i = 0;
        while (i < 100)
        {
            if (!used)
            {
                used = true;
                line.color(color);
                return true;
            }
            else
            {
                try
                {
                    wait(10);
                }
                catch (InterruptedException e)
                {
                    Thread.currentThread().interrupt();
                }
                i++;
            }
        }
        return false;
    }

    /**
     * Die Gabel wird abgelegt; da sie dann keinen Besitzer mehr hat, wird ihre
     * Farbe auf "schwarz" gesetzt.
     */
    synchronized void putDown()
    {
        used = false;
        line.color("schwarz");
        notifyAll();
    }

    public static void main(String[] args)
    {
        Controller.instantMode(false);
        Controller.start(new DiningPhilosophers(5), 800, 800);
    }
}
Zum Java-Code: demos//home/runner/work/engine-pi/engine-pi/subprojects/demos/src/main/java/demos/edu_projects/concurrency/philosophers/Fork.java

/*
 * Engine Pi ist eine anfängerorientierte 2D-Gaming Engine.
 *
 * Copyright (c) 2026 Josef Friedrich and contributors.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 */
package demos.edu_projects.concurrency.philosophers;

import java.awt.Graphics2D;
import java.util.List;

import pi.Controller;
import pi.Scene;
import pi.actor.StopWatch;
import pi.event.FrameListener;
import pi.graphics.boxes.TextTableBox;

// Go to file:///data/school/repos/inf/java/engine-pi/docs/manual/projects/philosophers.md

/**
 * Visualisierung des Problems der speisenden Philosophen.
 *
 * @author Johannes Neumeyer
 * @author Josef Friedrich
 *
 * @version 1.0
 */
class DiningPhilosophers extends Scene implements FrameListener
{
    /**
     * Die zufällig ausgewählten Philosophen, die am Tisch essen.
     */
    private List<Philosopher> philosophers;

    /**
     * Verhungern die Philosophen?
     */
    boolean starving = false;

    StopWatch stopWatch;

    TextTableBox table;

    /**
     * Beteiligte Objekte (Philosophen, Teller, Gabeln, ...) werden passend
     * erstellt und die Philosophenthreads gestartet.
     *
     * @param count Die Anzahl der Philosophen, die am Tisch sitzen und essen.
     */
    DiningPhilosophers(int count)
    {
        info().description(
            "Abgelegte Gabeln sind schwarz, aufgenommene Gabeln haben die Farbe ihres aktuellen Besitzers.");

        // Die die Philosophenbilder eine weiße Hintergrundfarbe und die
        // Philosophen nicht freigestellt sind, verwenden wir als
        // Hintergrundfarbe für die Szene weiß.
        backgroundColor("weiß");

        philosophers = new PhilosophersCollection().select(count);

        new Table(this, philosophers);

        stopWatch = (StopWatch) new StopWatch().start()
            .anchor(-10, 10)
            .color("black");
        add(stopWatch);

        table = new TextTableBox();
        table.columns(2).anchor(600, 600);
        table.padding(5);

        for (Philosopher philosopher : philosophers)
        {
            philosopher.start();

            table.addCell(philosopher.name());
            table.addCell(philosopher.eatCounter());
        }

    }

    @Override
    public void renderOverlay(Graphics2D g, int width, int height)
    {
        for (int i = 0; i < philosophers.size(); i++)
        {
            final Philosopher philosopher = philosophers.get(i);
            table.forBox(i,
                1,
                cell -> cell.box.content(philosopher.eatCounter()));
        }
        table.render(g);
    }

    @Override
    public void onFrame(double pastTime)
    {
        starving = true;
        for (Philosopher philosopher : philosophers)
        {
            if (!philosopher.isStarving())
            {
                starving = false;
            }
        }

        if (starving)
        {
            stopWatch.stop();
        }
        else
        {
            stopWatch.start();
        }
    }

    public static void main(String[] args)
    {
        Controller.instantMode(false);
        Controller.start(new DiningPhilosophers(5), 800, 800);
    }
}
Zum Java-Code: demos//home/runner/work/engine-pi/engine-pi/subprojects/demos/src/main/java/demos/edu_projects/concurrency/philosophers/DiningPhilosophers.java


  1. Bei manchen Philosophen ist das genaue Geburts- und Sterbejahr nicht bekannt. Die Angaben zu den Lebensdaten sind ohne Gewähr. Die verlinkten Wikipedia-Artikel sind eine zuverlässlichere Quelle als diese Tabelle. 

  2. Eine Minus vor den Jahreszahlen bedeutet „vor Christus“ 

  3. Die Farben wurden nach dem Bilder aus Kids Vector Characters Collection. Set of 26 Great Philosophers and Thinkers of History in cartoon style genommen.