当前位置: 首页 > 知识库问答 >
问题:

用餐哲学家在爪哇

李锦
2023-03-14

今天,我决定尝试解决哲学家吃饭的问题。所以我写下面的代码。但我认为这是不正确的,所以如果有人告诉我这是怎么回事,我会很高兴的。我使用fork作为锁(我只读取它们,因为我不把对它们的访问放在同步块中),我有一个扩展线程的类,它保留了它的两个锁。

import java.util.Random;

public class EatingPhilosophersProblem {

private final static Random RANDOM = new Random();

/**
 * 
 * @author Damyan Class represents eating of every philosopher. It
 *         represents infinity cycle of eating.
 */
private static class PhilosopherEating extends Thread {

    int forkOne;
    int forkTwo;

    public PhilosopherEating(String name, int forkOne, int forkTwo) {
        super(name);
        this.forkOne = forkOne;
        this.forkTwo = forkTwo;
    }

    @Override
    public void run() {
        super.run();

        while (true) {
            requireLock(this, forkOne, forkTwo);
        }
    }

}

private static Boolean[] forks = new Boolean[] { new Boolean(true), new Boolean(true), new Boolean(true),
        new Boolean(true), new Boolean(true) };
// locks should be created by new, otherwise almost 100% sure that they will
// point to the same object (because of java pools)
// this pools are used from java for immutable objects

private static void requireLock(PhilosopherEating philosopherEating, int firstIndex, int secondIndex) {

    // we lock always from the the lower index to the higher, otherwise
    // every philosopher can take his left fork and deadlock will apear

    if (firstIndex > secondIndex) {
        int temp = firstIndex;
        firstIndex = secondIndex;
        secondIndex = temp;
    }

    if (firstIndex == 4 || secondIndex == 4) {
        System.err.println(firstIndex + " and " + secondIndex);
    }

    synchronized (forks[firstIndex]) {
        synchronized (forks[secondIndex]) {

            printPhilosopherhAction(philosopherEating, "start eating");

            try {
                Thread.sleep(RANDOM.nextInt(100));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            printPhilosopherhAction(philosopherEating, "stop eating");

        }
    }
};

private static void printPhilosopherhAction(PhilosopherEating philosopherEating, String action) {
    System.out.println("Philosopher " + philosopherEating.getName() + " " + action);

}

public static void main(String[] args) {

    PhilosopherEating first = new PhilosopherEating("1 - first", 0, 1);
    PhilosopherEating second = new PhilosopherEating("2 - second", 1, 2);
    PhilosopherEating third = new PhilosopherEating("3 - third", 2, 3);
    PhilosopherEating fourth = new PhilosopherEating("4 - fourth", 3, 4);
    PhilosopherEating fifth = new PhilosopherEating("5 - fifth", 4, 0);

    first.start();
    second.start();
    third.start();
    fourth.start();
    fifth.start();

}

我认为有些不对劲,因为第五位哲学家从不吃饭,第四位和第三位哲学家大多吃饭。提前感谢。

共有2个答案

汲雅珺
2023-03-14

当哲学家吃饭时,你会锁上一段随机的时间,但是你会不断循环,所以当其他线程收到解除锁的通知时,你的第一个哲学家又开始吃饭了。如果我修改你的代码,在锁外进食后随机等待:

requireLock(this, forkOne, forkTwo);
try {
  Thread.sleep(RANDOM.nextInt(100));
} catch (InterruptedException e) {
  e.printStackTrace();
}

我看到所有的哲学家都更擅长依次进食。

龚浩宕
2023-03-14

您的问题有一个名称:它被称为线程“饥饿”。这是当多个线程竞争同一资源时,其中一个(或多个)连续被拒绝访问时发生的情况。

弄清楚如何避免僵局是用餐哲学家难题的一个方面,但弄清楚如何让每个哲学家获得公平的用餐时间可能是另一个方面。

JP Moresmau的回答建议你强迫每个哲学家Rest一下(在经典谜题中通常称为“思考”),这样其他哲学家就可以轮到吃饭了。这是可行的,但是如果你认为你的哲学家在某些应用程序中是工作线程,那么“吃”对应于工作线程做一些有用的工作,“Rest”或“思考”对应于空闲的线程,这可能是你希望避免的。

如果所有的哲学家总是饥饿,要确保所有的哲学家都有公平的吃饭时间,不仅仅需要锁。

这里有一个提示:使任何类型的“公平性”得到保证的更高级别的同步对象通常在实现中使用队列。

 类似资料:
  • 我的Java代码中有一个问题,它应该模拟pholosophers问题,如下所述:http://en.wikipedia.org/wiki/Dining_philosophers_problem我想输出所有哲学家的当前状态,每次他们中的一个吃饭或思考。输出应该是这样的:“OxOx(2)”,其中“X”表示哲学家在吃,“O”表示他在思考,“O”表示他在等筷子。括号中的数字表示状态已更改的哲学家的编号。我

  • 本文向大家介绍餐饮哲学家问题(DPP),包括了餐饮哲学家问题(DPP)的使用技巧和注意事项,需要的朋友参考一下 餐饮哲学家的问题指出,有5位哲学家共享一张圆桌,他们交替吃饭和思考。每个哲学家都有一碗饭和5根筷子。哲学家需要左右筷子才能吃饭。饿了的哲学家只有在两把筷子都齐备的情况下才可以吃东西,否则哲学家放下筷子,重新开始思考。 餐饮哲学家是一个经典的同步问题,因为它演示了一大类并发控制问题。 餐饮

  • 我必须用信号量来解决这个问题。在我的代码中,每一个哲学家都在拿一根筷子,其他人都在等待。 我在主函数中仍然有一些错误。你能告诉我怎么使用筷子吗?我是BACI的初学者。

  • 我们有一个任务来说明这个问题的僵局。我们已经编写了所有代码,并且代码可以编译,但是当运行代码时,一位哲学家最终吃了东西。所以这不意味着死锁实际上不会发生吗? 这就是输出:输出

  • 我想用java信号量解决用餐哲学家的问题,但我被卡住了。最高ID的筷子应该是可用的,但它似乎总是采取,我不知道为什么。谁能告诉我我错在哪里了? Fork类: 哲学家班: 主要内容:

  • 根据这篇维基百科文章中的钱迪/米斯拉部分,我们有5位哲学家,编号为P1-P5。 根据这句话: 对于每一对争夺资源的哲学家,创建一个叉子,并将其交给具有较低ID的哲学家(n代表代理Pn)。每个叉子可以是脏的或干净的。最初所有的叉子都是脏的 当一个有叉子的哲学家收到一个请求消息时,如果叉子是干净的,他会保留它,但是如果叉子是脏的,他会放弃它。如果他把叉子送过去,他会先把叉子清理干净。 因此,如果知道所