哲学家进餐问题,是并发执行共享资源的代表性问题。
某天有五位沉默寡言的哲学家围在一张桌子上吃饭,他们在吃饭和想吃饭的路上。 桌子上有五根筷子,每个人的左手边都有一只筷子。
吃饭嘛就得有两根筷子才能吃,但是每个人都先抢左手筷子再抢右手筷子,抢完左手筷子体力不行了休息一秒再接着抢。不出所料,右手筷子已经被别人给抢了,每个哲学家都轴得很就是不让左手的筷子,大不了一起“饿死”,此时就产生了死锁
。
如何用java重现这个场景呢?
通过面向对象的思想就很简单。这个场景中,主要有了两个对象,筷子与哲学家。
public class ChopSticks{
private String name;
public void setName(String name){
this.name = name
}
public String getName(){
return name;
}
}
筷子对象就比较简单。哲学家对象呢,本身就是一个线程,然后有左手、右手、座位号、名称等属性。左右手指的是左右手边的筷子。
public class Philosopher extends Thread{
private ChopSticks right,left;
private String name;
private int index;
public Philosopher(String name,int index,ChopSticks right,ChopSticks left) {
this.name = name;
this.index = index;
this.right = right;
this.left = left;
}
@Override
public void run(){
synchronized (left){
sleep(index+1000);//抢到左手筷子,累了休息一会再抢右手筷子。
synchronized (right){//开始抢右手筷子,不出意料,被别人抢了。就这样就产生了死锁。
sleep(1);
System.out.println(index+"吃完了");
}
}
}
}
每个人都不肯松开左手的筷子,怎么会这么犟呢?再这样下去就都饿死啦,好了重新开始抢,不要再打盹了哦。
有两种解决方式(实际有三种,最后一种忘记了
)
- 同时抢左右手筷子,就不要还想着矜持了,先抢再说。
synchronized (left){
synchronized (right){
sleep(1000);
System.out.println(index+"吃完了");
}
}
- 第一个人抢右手筷子,剩余的抢左手筷子。
if(index==0){
synchronized (right){
sleep(index+1000)
synchronized (left){
sleep(1000);
System.out.println(index+"吃完了");
}
}
}else{
synchronized (left){
sleep(index+1000)
synchronized (right){
sleep(1000);
System.out.println(index+"吃完了");
}
}
}
每个哲学家都吃饱饭了,可以接着想更哲学的问题了。