一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
1。什么是哲学家就餐问题
有五位沉默的哲学家围坐在一张圆桌旁,他们一生都在吃东西和思考。有五只筷子供他们使用,哲学家需要双手拿到一双筷子之后才能吃饭;吃完后会将筷子放下继续思考。那么现在有一个问题,我们需要想出一种方案,如何保证哲学家们可以交替吃饭和思考,而不会被饿死。
2.解决方案
2.1解决方案1 锁粗化
思路:将五把筷子看成一把锁,每次一个哲学家吃,吃完第二个吃,如此就解决了
2.2解决方案2 面向对象思维
构建筷子对象和 哲学家对象 哲学家对象的属性包括左边的筷子和右边的筷子
在执行时先去抢左手边的筷子 再去抢右手边的筷子,若都抢到 则可以吃饭,用synchronized(left) 和synchronized(right)来模拟抢筷子操作
哲学家类定义如下:
public class Philosopher extends Thread{
//z左右筷子
private Chopstick left,right;
//编号
private Integer index;
public Philosopher(String name ,Chopstick left, Chopstick right, Integer index) {
this.setName(name);
this.left = left;
this.right = right;
this.index = index;
}
@Override
public void run() {
if(index%2==1){
synchronized (right){
synchronized (left){
System.out.println(index+"号吃完了");
}
}
} else {
synchronized (left){
synchronized (right){
System.out.println(index+"号吃完了");
}
}
}
}
}
先构建五位哲学家 顺序和筷子依次摆放,让每个哲学家左右手都有一只筷子,然后启动线程 实现如下
public class TestEat {
public static void main(String[] args) {
Chopstick cs1 =new Chopstick();
Chopstick cs2 =new Chopstick();
Chopstick cs3 =new Chopstick();
Chopstick cs4 =new Chopstick();
Chopstick cs5 =new Chopstick();
Philosopher philosopher1 =new Philosopher("p1",cs1,cs2,1);
Philosopher philosopher2 =new Philosopher("p2",cs2,cs3,2);
Philosopher philosopher3 =new Philosopher("p3",cs3,cs4,3);
Philosopher philosopher4 =new Philosopher("p4",cs4,cs5,4);
Philosopher philosopher5 =new Philosopher("p5",cs5,cs1,5);
philosopher1.start();
philosopher2.start();
philosopher3.start();
philosopher4.start();
philosopher5.start();
}
}
结果如下:
2.3 死锁问题的解决
很明显 当五个哲学家开始抢筷子的时候 如果同时抢到了右边的筷子 那么就会进入死锁 都抢不到左边的 ,代码将会卡死。
解决方案:混进一个左撇子
定义一个哲学家从左边开始抢筷子 那么就不会有人同时抢到右边筷子 导致死锁
优化:抢筷子分奇偶 奇数哲学家从左边开始抢 偶数从右边开始抢