哲学家就餐问题(看完不会你打我)——java实现

哲学家就餐问题–看完不会你打我

以synchronized为例演示都吃不上饭

  1. 定义筷子类

    class Chopstic {
        private final String name;
    
        public String getName() {
            return name;
        }
    
        public Chopstic(String name) {
            this.name = name;
        }
    }
    
  2. 定义哲学家类

    class Philosophe extends Thread {
        private final Chopstic left;
        private final Chopstic right;
    
        public Philosophe(String name, Chopstic left, Chopstic right) {
            super(name);
            this.left = left;
            this.right = right;
        }
    
        @Override
        public void run() {
            while (true) {
                synchronized (left) {
                    synchronized (right) {
                        System.out.println(getName() + " 拿起了 " + left.getName() + " 和 " + right.getName()+" 筷子 开始吃饭");
                    }
                }
            }
        }
    }
    
  3. 测试

        public static void main(String[] args) {
            Chopstic c1 = new Chopstic("1");
            Chopstic c2 = new Chopstic("2");
            Chopstic c3 = new Chopstic("3");
            Chopstic c4 = new Chopstic("4");
            Chopstic c5 = new Chopstic("5");
            new Philosophe("苏格拉底", c1, c2).start();
            new Philosophe("柏拉图", c2, c3).start();
            new Philosophe("亚里士多德", c3, c4).start();
            new Philosophe("赫拉克利特", c4, c5).start();
            new Philosophe("阿基米德", c5, c1).start();
        }
    

    在这里插入图片描述

使用jconsole检测死锁,发现死锁

在这里插入图片描述

苏格拉底等待柏拉图,柏拉图等待亚里士多德 ,。。。。

正确解答

解决思路就是:无论已经有几个筷子了,一旦当前的筷子获取不到,不等待,直接放弃,把筷子全部释放,重新获取筷子

ReentrantLock的API正合适

  1. 定义筷子类 (继承ReentrantLock)

    class Chopstick extends ReentrantLock {
        private final String name;
    
        public String getName() {
            return name;
        }
    
        public Chopstick(String name) {
            this.name = name;
        }
    }
    
  2. 定义哲学家类

    例如:左手的筷子已经拿到了,去拿右手的筷子时失败了,if条件不成立,程序继续运行,执行finally块,解锁左手的筷子。

    class Philosopher extends Thread {
        private final Chopstick left;
        private final Chopstick right;
    
        public Philosopher(String name, Chopstick left, Chopstick right) {
            super(name);
            this.left = left;
            this.right = right;
        }
    
        @Override
        public void run() {
            while (true) {
                if (left.tryLock()) {
                    try {
                        if (right.tryLock()) {
                            try {
                                System.out.println(Thread.currentThread().getName()+"   \n左手:"+this.left.getName()+" 右手:"+right.getName() + " is eating.");
                            } finally {
                                right.unlock();
                            }
                        }
                    } finally {
                        left.unlock();
                    }
                }
            }
        }
    }
    
  3. 测试

        public static void main(String[] args) {
            Chopstick c1 = new Chopstick("1");
            Chopstick c2 = new Chopstick("2");
            Chopstick c3 = new Chopstick("3");
            Chopstick c4 = new Chopstick("4");
            Chopstick c5 = new Chopstick("5");
            new Philosopher("苏格拉底", c1, c2).start();
            new Philosopher("柏拉图", c2, c3).start();
            new Philosopher("亚里士多德", c3, c4).start();
            new Philosopher("赫拉克利特", c4, c5).start();
            new Philosopher("阿基米德", c5, c1).start();
    
        }
    

    没有发现死锁
    在这里插入图片描述

  • 15
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
哲学家进餐问题是一个经典的同步问题,主要涉及到多个进程(哲学家)之间的资源竞争问题。在这个问题中,每个哲学家都需要交替地进行思考和进餐,但是他们共享一些资源,如餐具等,因此需要协调它们的行为以避免死锁和饥饿等问题。 下面是使用 Java 实现哲学家进餐问题的示例代码: ```java import java.util.concurrent.Semaphore; public class Philosopher implements Runnable { private final int id; private final Semaphore leftFork; private final Semaphore rightFork; public Philosopher(int id, Semaphore leftFork, Semaphore rightFork) { this.id = id; this.leftFork = leftFork; this.rightFork = rightFork; } @Override public void run() { try { while (true) { think(); leftFork.acquire(); rightFork.acquire(); eat(); rightFork.release(); leftFork.release(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); return; } } private void think() throws InterruptedException { System.out.println("Philosopher " + id + " is thinking"); Thread.sleep((long) (Math.random() * 5000)); } private void eat() throws InterruptedException { System.out.println("Philosopher " + id + " is eating"); Thread.sleep((long) (Math.random() * 5000)); } } public class DiningPhilosophers { private static final int NUM_PHILOSOPHERS = 5; public static void main(String[] args) { Semaphore[] forks = new Semaphore[NUM_PHILOSOPHERS]; for (int i = 0; i < NUM_PHILOSOPHERS; i++) { forks[i] = new Semaphore(1); } Philosopher[] philosophers = new Philosopher[NUM_PHILOSOPHERS]; for (int i = 0; i < NUM_PHILOSOPHERS; i++) { philosophers[i] = new Philosopher(i, forks[i], forks[(i + 1) % NUM_PHILOSOPHERS]); new Thread(philosophers[i]).start(); } } } ``` 在这个示例代码中,我们创建了一个 `Philosopher` 类和一个 `DiningPhilosophers` 类,其中 `Philosopher` 类实现了哲学家的行为,而 `DiningPhilosophers` 类则负责创建和启动哲学家线程。 在 `Philosopher` 类中,我们使用了两个信号量 `leftFork` 和 `rightFork` 表示哲学家左边和右边的餐叉。在 `run` 方法中,哲学家先思考一段时间,然后尝试获取左右餐叉的信号量。如果成功获取了两个餐叉的信号量,哲学家就可以进餐。最后,哲学家释放左右餐叉的信号量,以便其他哲学家可以使用它们。 在 `DiningPhilosophers` 类中,我们首先创建了一个 `Semaphore` 数组 `forks`,其中每个元素都表示一个餐叉。然后,我们创建了五个 `Philosopher` 对象,并将它们的左右餐叉设置为相邻的两个 `Semaphore` 对象。最后,我们创建了五个线程,每个线程都对应一个哲学家,并启动它们。当程序运行时,每个哲学家会交替进行思考和进餐,直到程序被中断或终止。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值