问题描述
哲学家就餐问题可以这样表述,假设有五位哲学家围坐在一张圆形餐桌旁,做以下两件事情之一:吃饭,或者思考。吃东西的时候,他们就停止思考,思考的时候也停止吃东西。餐桌中间有一大碗意大利面,每两个哲学家之间有一只餐叉。因为用一只餐叉很难吃到意大利面,所以假设哲学家必须用两只餐叉吃东西。他们只能使用自己左右手边的那两只餐叉。哲学家就餐问题有时也用米饭和筷子而不是意大利面和餐叉来描述,因为很明显,吃米饭必须用两根筷子。
哲学家从来不交谈,这就很危险,可能产生死锁,每个哲学家都拿着左手的餐叉,永远都在等右边的餐叉(或者相反)。即使没有死锁,也有可能发生资源耗尽。例如,假设规定当哲学家等待另一只餐叉超过五分钟后就放下自己手里的那一只餐叉,并且再等五分钟后进行下一次尝试。这个策略消除了死锁(系统总会进入到下一个状态),但仍然有可能发生“活锁”。如果五位哲学家在完全相同的时刻进入餐厅,并同时拿起左边的餐叉,那么这些哲学家就会等待五分钟,同时放下手中的餐叉,再等五分钟,又同时拿起这些餐叉。
解决方案
既然哲学家自己不能吃饭,那我们就找个服务员,当服务员通知他们某个人可以吃饭时,收到通知的人便拿起两边的筷子开始吃饭,这样同时最多可能有两位哲学家在吃饭,另外三个人在思考。那么服务员是怎么确定他们是如何吃饭的呢?
服务员可以先确认一下哲学家两边的筷子是否都没有人使用,若是,则通知哲学家拿起筷子吃饭,若有一个筷子被其它哲学家使用,那么这个哲学家就继续思考。
算法实现
/**
* 哲学家类
*/
class Philosopher extends Thread{
private String name;
private Fork fork;
public Philosopher(String name,Fork fork){
super(name);//线程的名字
this.name = name;
this.fork = fork;
}
/**
* 吃饭
*/
public void eating(){
/**
* 吃饭
*/
System.out.println("i'm eating:"+name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/**
* 思考
*/
public void thinking(){
System.out.println("i'm thinking:"+name);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void run(){
while(true){
/**
* 思考
*/
thinking();
/**
* 拿筷子
*/
fork.takeFork();
/**
* 吃饭
*/
eating();
/**
* 放筷子
*/
fork.putFork();
}
}
}
class Fork{
/**
* 筷子数组
*/
private boolean fork[] = {false,false,false,false,false};
/**
* 拿起筷子
*/
public synchronized void takeFork(){
String name = Thread.currentThread().getName();
int i = Integer.parseInt(name);
//任意一个筷子被人使用
while(fork[i] || fork[(i+1) % 5]){
try {
wait();//线程等待
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
fork[i] = true;
fork[(i+1) % 5] = true;
}
/**
* 放下筷子
*/
public synchronized void putFork(){
String name = Thread.currentThread().getName();
int i = Integer.parseInt(name);
fork[i] = false;
fork[(i+1) % 5] = false;
notifyAll();//唤醒其它线程
}
}
public class Demo7 {
public static void main(String[] args) {
Fork f = new Fork();
new Philosopher("0", f).start();
new Philosopher("1", f).start();
new Philosopher("2", f).start();
new Philosopher("3", f).start();
new Philosopher("4", f).start();
}
}
运行结果
i'm thinking:1
i'm thinking:2
i'm thinking:0
i'm thinking:3
i'm thinking:4
i'm eating:1
i'm eating:3
i'm thinking:1
i'm eating:0
i'm eating:2
i'm thinking:3
i'm eating:4
i'm thinking:0
i'm thinking:2
i'm eating:1