JAVA-从面向对象看哲学家就餐问题

197 阅读2分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 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();
    }
}

结果如下:

image.png

2.3 死锁问题的解决

很明显 当五个哲学家开始抢筷子的时候 如果同时抢到了右边的筷子 那么就会进入死锁 都抢不到左边的 ,代码将会卡死。

解决方案:混进一个左撇子

定义一个哲学家从左边开始抢筷子 那么就不会有人同时抢到右边筷子 导致死锁

优化:抢筷子分奇偶 奇数哲学家从左边开始抢 偶数从右边开始抢