一. 问题描述
5个哲学家,5跟筷子,哲学家必须用两只筷子吃东西。他们只能使用自己左右手边的那两只筷子。做到不产生死锁以及要求高并发性。
二. 资源加锁法
直接给所请求的资源加锁,其他人想访问必须等待;
package psy;
/**
* 哲学家线程
* @author stephenluu
*
*/
public class PerThread extends Thread {
private static int[] chopstick = { 1, 1, 1, 1, 1 };
private int i;
public PerThread(int i) {
this.i = i;
}
@Override
public void run() {
synchronized (chopstick) { //若注释此行,打开下行,不同步,5个per只拿到左筷子
//{
eat(this.getName());
think(this.getName());
}
}
private void think(String name) {
chopstick[i] = 1;
chopstick[(i + 1) % 5] = 1;
System.out.println("per"+name+" is thinking...");
}
private void eat(String string) {
while (true) {
if (chopstick[i] != 0) {
chopstick[i]--;
System.out.println("per" + this.getName()
+ " got left chopstick.");
break;
}
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (true) {
if (chopstick[(i + 1) % 5] != 0) {
chopstick[(i + 1) % 5]--;
System.out.println("per" + this.getName()
+ " got right chopstick.");
break;
}
}
System.out.println("per" + string + " is eating...");
}
}
测试类
package psy;
/**
* 解决哲学家进餐问题
* @author stephenluu
*
*/
public class MainTest {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
Thread t = new PerThread(i);
t.start();
}
}
}
效果:
perThread-0 got left chopstick.
perThread-0 got right chopstick.
perThread-0 is eating...
perThread-0 is thinking...
perThread-4 got left chopstick.
perThread-4 got right chopstick.
perThread-4 is eating...
perThread-4 is thinking...
perThread-3 got left chopstick.
perThread-3 got right chopstick.
perThread-3 is eating...
perThread-3 is thinking...
perThread-2 got left chopstick.
perThread-2 got right chopstick.
perThread-2 is eating...
perThread-2 is thinking...
perThread-1 got left chopstick.
perThread-1 got right chopstick.
perThread-1 is eating...
perThread-1 is thinking...
这样死锁就不会产生的了,但是会不会太浪费资源啊?! 还有效率也慢。
三.超时释放法
假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只筷子,并且再等五分钟后进行下一次尝试。这个策略也消除了死锁。
package perEat;
/**
* 哲学家线程
* @author stephenluu
*
*/
public class PerThread extends Thread {
private static int[] chopstick = {1,1,1,1,1};
private int i;
private int n = 5;
public PerThread(int i) {
this.i = i;
}
@Override
public void run() {
//拿左筷子
synchronized (chopstick) {
while (chopstick[i] == 0) {
try {
chopstick.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
chopstick[i]--;
System.out.println("per" + this.getName()
+ " got left chopstick.");
chopstick.notify();
}
// 睡一下产生死锁
try {
Thread.sleep((long) (Math.random()*1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
//拿右筷子
synchronized (chopstick) {
while (chopstick[(i + 1) % n] == 0) {
try {
chopstick.wait(3*1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
finally{
System.out.println(this.getName()+" waited 3s ,free left chopstick");
chopstick[i] ++;
}
}
chopstick[(i + 1) % n]--;
System.out.println("per" + this.getName()
+ " got right chopstick.");
System.out.println("per" + this.getName() + " is eating...");
chopstick[i]++;
chopstick[(i + 1) % n]++;
System.out.println("per"+this.getName()+" is thinking...");
chopstick.notify();
}
}
}
测试类
package perEat;
/**
* 解决哲学家进餐问题
* @author stephenluu
*
*/
public class MainTest {
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
Thread t = new PerThread(i);
t.start();
}
}
}
效果:
perThread-0 got left chopstick.
perThread-2 got left chopstick.
perThread-3 got left chopstick.
perThread-4 got left chopstick.
perThread-1 got left chopstick.
Thread-3 waited 3s ,free left chopstick
Thread-0 waited 3s ,free left chopstick
Thread-1 waited 3s ,free left chopstick
Thread-4 waited 3s ,free left chopstick
perThread-4 got right chopstick.
perThread-4 is eating...
perThread-4 is thinking...
Thread-2 waited 3s ,free left chopstick
perThread-2 got right chopstick.
perThread-2 is eating...
perThread-2 is thinking...
Thread-3 waited 3s ,free left chopstick
perThread-3 got right chopstick.
perThread-3 is eating...
perThread-3 is thinking...
Thread-0 waited 3s ,free left chopstick
perThread-0 got right chopstick.
perThread-0 is eating...
perThread-0 is thinking...
Thread-1 waited 3s ,free left chopstick
perThread-1 got right chopstick.
perThread-1 is eating...
perThread-1 is thinking...
并发性比第一种好。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的筷子,那么这些哲学家就会等待五分钟,同时放下手中的筷子,再等五分钟,又同时拿起这些筷子。。。。。。
四.
最初是张龙说,5个哲学家都拿起左筷子,产生死锁,最后全部哲学家都饿死了! 觉得挺有趣,加上《操作系统》课程有提到,今天下午研究了一下,能力有限,只写出“资源加锁”和“超时释放”两种方法,至于百度百科的三种“正确”的解决方法:服务生解法,资源分级法,和Chandy/Misra解法,有机会在尝试下。
分享到:
相关推荐
哲学家进餐问题(Dining Philosophers Problem)是计算机科学中的一个经典同步问题,由艾兹格·迪科斯彻提出,旨在探讨并发系统中资源竞争与死锁的问题。在这个问题中,五个哲学家围坐在一张圆桌旁,每个人面前都有...
在这个解决方案中,"图形界面"使得问题的展示更为直观,用户可以观察到哲学家们的行为和筷子的状态。重庆大学的学生可能会对此特别感兴趣,因为这可能与他们的课程或项目相关。 信号量是一种用于控制对共享资源访问...
哲学家就餐问题是多线程编程中的一个经典示例,它由计算机科学家Edsger Dijkstra提出,用于模拟并发环境中可能出现的死锁问题。在该问题中,五个哲学家围坐在一张圆桌旁,每个人面前有一根筷子。当哲学家想要吃饭时...
**JAVA管程解决哲学家就餐问题** 在计算机科学中,"哲学家就餐问题"是一个经典的多线程同步问题,由Edsger W. Dijkstra在1965年提出。这个问题描述了五个哲学家围坐在一张圆桌旁,每个人面前都有一只筷子。当哲学家...
《Java 解决哲学家就餐问题》 在计算机科学和多线程编程中,哲学家就餐问题是一个经典的示例,用于探讨线程同步、互斥以及如何避免死锁的问题。问题描述如下:五个哲学家围坐在一张圆桌旁,每个人面前有一盘面,两...
在操作系统领域,C#可以用来编写控制并发行为的程序,虽然它不如C++或Java常见,但仍然能有效地解决哲学家进餐问题。 C#中实现并发控制的关键在于线程同步机制。在本案例中,可能使用了`Monitor`类,它是.NET框架...
在"philosopher"这个文件夹中,可能包含了一个Java项目,该项目实现了上述的哲学家问题解决方案。项目可能包括以下组件: 1. `Philosopher`类:代表一个哲学家线程,包含获取和释放筷子的逻辑。 2. `Fork`类:表示...
总结来说,模拟哲学家进餐问题是一个引人深思的并发控制模型,它帮助我们理解和解决实际系统中的并发和死锁问题。通过对这个问题的研究,我们可以学习到如何设计和实现高效、安全的多线程应用程序,这对于现代计算机...
综上所述,利用管程概念解决哲学家进餐问题,不仅提高了程序的模块化和可读性,还通过Java的高级并发对象提供了精确的线程同步和唤醒机制,有效地防止了死锁的发生。这种方法对于理解和处理并发控制问题具有重要的...
- **先取低编号筷子**:让哲学家先尝试取编号较小的筷子,这样至少有一个哲学家可以拿到两根筷子,避免全部哲学家等待。 - **避免同时思考**:引入随机思考时间,减少所有哲学家同时饿的可能性。 - **哲学家的...
哲学家进餐问题是计算机科学中一个经典的问题,用于模拟并发控制和死锁的场景。它由计算机科学家Edsger Dijkstra在1965年提出,用来探讨多线程环境下的资源分配策略。在这个问题中,五位哲学家围坐在一张圆桌旁,...
"哲学家进餐问题"是计算机科学中一个经典的多线程同步问题,源自于数学家和哲学家笛卡尔的生活场景。在这个问题中,有五个哲学家围坐在一张圆桌旁,每人面前都有一根筷子。当哲学家思考时,他们不需要筷子;但当他们...
在计算机科学领域,多线程是并发...通过解决哲学家就餐问题,我们可以学习到如何在多线程环境中有效地管理资源,防止死锁,并理解Java的线程同步机制。这个经典实例对于理解和解决更复杂的并发问题有着重要的指导意义。
我们将通过编程模拟这个场景,以实现一个能够解决哲学家进餐问题的模型。以下是可能涉及的关键知识点: 1. **并发控制**:并发是指多个任务在同一时间间隔内执行,但不一定是真正意义上的同时执行。在操作系统中,...
Java哲学家就餐问题是一个经典的多线程同步问题,源自计算机科学中的并发控制理论。...通过解决Java哲学家就餐问题,开发者能深入理解多线程编程中的同步与通信,这对于开发高并发的Java应用至关重要。
"哲学家就餐问题"(Dining Philosophers Problem)就是一个经典的并发问题,由艾兹格·迪科斯彻在1965年提出,它形象地模拟了五个哲学家围坐一桌,各自思考问题,同时需要用餐的场景。本篇将深入探讨如何利用多线程...
在这个Java实现的版本中,我们可以通过使用线程、同步机制(如synchronized关键字)、信号量(Semaphore)或者等待/通知机制(wait()和notify())来解决哲学家进餐问题。 1. **线程**:每个哲学家可以被表示为一个...