Java 中的哲学家就餐问题及解决方案2025 年 9 月 4 日 | 阅读 6 分钟 哲学家就餐问题是关于竞争进程之间有限资源分配的并发问题的一个例子。在本节中,我们将了解 如何在哲学家就餐问题中避免死锁。这是并发系统中一个不希望出现的情况。它表现为循环等待状态。首先,我们将讨论操作系统中使用的哲学家就餐问题,然后我们将转向解决方案。此外,我们还将用 Java 程序实现解决方案。 哲学家就餐问题问题的图示如下。 ![]() 上图表示有五位哲学家(标记为 P1、P2、P3、P4 和 P5)围坐在一张圆形的餐桌旁。有五盘面条供哲学家感到饥饿时食用。为了吃面条,每位哲学家之间放置着五副叉子/筷子(标记为 1 到 5)。 每位哲学家轮流吃饭和思考。每位哲学家都遵循以下条件:
最初,所有哲学家都在思考。过了一会儿,他们感到饥饿并想吃面条。哲学家会查看两边的叉子/筷子。当哲学家拿到两副叉子/筷子时,他开始吃饭。吃完后,他放下叉子/筷子,然后开始思考。当哲学家放下叉子/筷子时,相邻的哲学家可能会使用它们。 在这种情况下,可能会发生 死锁,即两个或多个进程无法继续执行的状态。该问题用于设计一种调度技术,以确保没有哲学家会挨饿。 哲学家就餐问题的解决方案哲学家就餐问题的解决方案是使用 信号量 (Semaphore)。它是用于并发进程的工具。使用信号量作为解决方案存在一个缺点。它可能导致死锁。假设一种情况是所有哲学家都先拿起左手的叉子/筷子,然后等待右手边的叉子/筷子。这种情况会导致死锁。 为了避免死锁,应采取一些措施:
哲学家就餐问题的实现在下面的程序中,我们首先初始化哲学家的数量(5)。两个数组 philosophers[] 和 chopsticks[] 都用哲学家数量(5)进行初始化。 为了实现筷子的逻辑,我们创建了一个名为 Chopstick 的类。在该类中,我们创建了 Semaphore 类的构造函数,并定义了三个方法:grab()、release() 和 isFree()。 grab() 方法调用 acquire() 方法,该方法从信号量获取一个许可。它会将许可数量减 1。如果没有可用的许可,则当前线程将禁用。 用户定义的 release() 方法调用 Semaphore 类的 release() 方法。它释放指定数量的许可,并将许可数量加 1。 isFree() 方法检查信号量中许可的可用性。它调用 Semaphore 类的 availablePermits() 方法,该方法返回信号量中可用的许可数量。 之后,我们创建了另一个名为 Philosopher 的类,该类扩展了 Thread 类。在该类中,我们定义了三个变量:number、leftchopstick 和 rightchopstick。此外,我们还创建了 Philosopher 类的构造函数和 eat() 方法。如果线程是使用单独的 Runnable 对象构造的,则会调用 Thread 类的 run() 方法。 当哲学家同时拥有左右两副筷子时,将执行 run() 方法。哲学家通过调用 eat() 方法开始吃饭,并持有叉子/筷子一段时间(睡眠时间)。为了确定睡眠时间,我们使用了 ThreadLocalRandom。current()。nextInt() 方法。该方法返回一个介于0到1000之间的伪随机、均匀分布的整数值。该值由传递给 sleep() 方法的 nextInt() 方法确定,该方法会将线程睡眠指定的时长。在本例中,如果睡眠时间超过 1000 毫秒,程序将退出。因此,我们可以设置伪随机数的范围(睡眠时间)。 在 main() 方法内部,我们定义了两个 for 循环:一个用于筷子,另一个用于哲学家。之后,我们检查死锁条件。如果发生死锁,则意味着每位哲学家都在通过获取筷子/叉子来吃饭。程序执行中断。只要资源(一根筷子)可用,死锁条件就不会发生。 DiningPhilosophersProblem.java 输出 ![]() 我们对上面的程序做一些小的改动。 在 while 循环内,将线程睡眠时间从1000更改为2000 毫秒。 现在执行上面的程序,我们将得到以下输出。 ![]() 注意:您可能会得到与上述输出不同的输出。因为每次执行程序时输出都会发生变化。 |
二进制字符串是仅包含 0 和 1 的数字序列。确定给定的二进制字符串是否代表 3 的倍数是一个在计算理论和有限自动机中的经典问题。最有效的方法之一是...
11 分钟阅读
使用各种方法可以在 Java 中将所有零移动到数组的开头。在这里,我们将探讨三种不同的方法:使用辅助数组、原地交换和双指针技术。每种方法都将得到解释,并附有完整的 Java 代码。方法...
5 分钟阅读
Java short 关键字是一种原始数据类型。它用于声明变量。它也可以与方法一起使用。它可以保存一个 16 位有符号二进制补码整数。要点:short 的最小值是 -32,768,最大值是 32,767...
阅读 6 分钟
在软件开发中,处理文件是一项经常性的工作,当需要管理多个文件或大型文件时,这项工作可能会变得效率低下。多线程是提高速度的关键方法,因为它允许多个线程同时执行工作。我们将检查 Java 中的多线程文件处理...
5 分钟阅读
Java 中的 switch 语句在最近的 Java 版本中进行了一些修改,以添加一些新功能。在本教程中,我们将讨论 Java 12 中的 switch 语句。但是,在此之前,让我们看一个展示实现的示例……
阅读 3 分钟
在快速发展的商业环境中,Java 已成为使用最广泛的编程语言之一。其多功能性、平台独立性和丰富的库使其成为开发健壮且可扩展的企业应用程序的首选。然而,与任何技术一样,Java 并非没有...
阅读 4 分钟
在 Java 中,当我们处理 String 时,有时需要使用特定的字符集对字符串进行编码。编码是从一种格式到另一种格式转换数据的一种方式。String 对象使用 UTF-16 编码。UTF-16 的问题在于它不能...
阅读 3 分钟
在 Java 中,List 是 Collection 框架的一个接口。它允许我们维护对象的有序集合。List 接口的实现类有 ArrayList、LinkedList、Stack 和 Vector。ArrayList 和 LinkedList 在 Java 中被广泛使用。在本节中,我们...
阅读 4 分钟
超级巨星困境是计算机科学中,特别是在算法问题解决领域中经常遇到的经典难题。这个问题可以概括如下。假设有一个有 N 个人的聚会。“名人”意味着每个人都知道某个人,但没有人知道其他人。目标是...
5 分钟阅读
在 Java 中,读写 Excel 文件有点棘手,因为 Excel 工作表有单元格来存储数据。Java 不提供直接读取或写入 Microsoft Excel 或 Word 文档的 API。我们必须依赖第三方库,该库...
阅读 3 分钟
我们请求您订阅我们的新闻通讯以获取最新更新。
我们提供所有技术(如 Java 教程、Android、Java 框架)的教程和面试问题
G-13, 2nd Floor, Sec-3, Noida, UP, 201301, India